FrankenPHP 部署 PHP

定位

FrankenPHP 是用 Go 写、内嵌 Caddy 的 PHP 应用服务器。它把 PHP 编译进一个常驻进程,对外提供 HTTP/2、HTTP/3、自动 HTTPS。

它不是框架,跟 Laravel 是配合关系。

最有价值的用法:frankenphp run 直接跑一个 Laravel/ThinkPHP 项目,不改一行业务代码,就把「每请求启动一次 PHP」变成「常驻 worker」。

安装

官方二进制(最简单)

curl https://frankenphp.dev/install.sh | sh
frankenphp version

Docker

FROM dunglas/frankenphp

COPY . /app/public
docker run -p 80:80 -p 443:443 -v $PWD:/app/public dunglas/frankenphp

两种运行模式

模式一:经典模式(兼容 FPM)

frankenphp php-server -r public/

每次请求都是一个全新的 PHP 执行环境,行为和 PHP-FPM 一致。迁移零风险,但拿不到常驻内存的好处。

模式二:Worker 模式(关键特性)

frankenphp php-server --worker public/index.php -r public/

public/index.php 只执行一次,然后循环处理请求:

<?php
// worker 脚本的固定结构(Laravel 的 octane 风格)
$handler = static function () {
    // 这段每次请求都执行
    require __DIR__ . '/../vendor/autoload.php';
    $app = require_once __DIR__ . '/../bootstrap/app.php';
    $kernel = $app->make(IlluminateContractsHttpKernel::class);
    $response = $kernel->handle($request = IlluminateHttpRequest::capture());
    $response->send();
    $kernel->terminate($request, $response);
};

// 关键:循环 + 判断是否退出
$maxRequests = (int) ($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; $nbRequests++) {
    $keepRunning = frankenphp_handle_request($handler);
    gc_collect_cycles();                 // 主动回收,避免内存累积
    if (!$keepRunning) break;
}

frankenphp_handle_request() 是核心函数:它阻塞等待下一个请求,执行回调,返回是否继续。

核心概念

1. Caddy 就是 Web 服务器

不需要 Nginx。Caddy 负责 TLS、HTTP/2/3、静态文件、反向代理,配置写在 Caddyfile:

example.com {
    root * /app/public
    encode zstd gzip
    php_server {
        worker /app/public/index.php
    }
}

自动 HTTPS 是 Caddy 的招牌功能,配好域名就自动申请续期证书。

2. Worker 模式的核心收益

FPMFrankenPHP Worker
每请求初始化框架是否(只初始化一次)
单机 QPS(中等项目)基准2-4 倍
内存按进程数常驻,比较稳定

收益来源很单纯:省掉了 autoload、容器启动、配置加载这些每请求都要做一遍的事。

3. 和 Swoole 的区别

FrankenPHPSwoole
实现语言GoC 扩展
并发模型Go 的 goroutinePHP 协程
业务代码要求不用改(worker 模式下注意状态残留)必须用协程化客户端
部署形态单进程内置 Web 服务器通常配合 Nginx

FrankenPHP 的门槛低得多:不用改代码、不用换数据库客户端,只是启动方式变了。

常见坑

① Worker 模式下的状态残留

和所有常驻内存方案一样:静态变量、全局单例会在请求间残留。Laravel 的 config、route 缓存是安全的,但你自己写的单例要注意。

② 内存泄漏

worker 会一直跑。内存缓慢上涨时,用 MAX_REQUESTS 定期重启 worker:

fastcgi / MAX_REQUESTS 500

③ 文件上传和 $_SERVER 的行为差异

worker 模式下 $_SERVER 来自第一个请求之后的状态,某些字段可能不准。用框架的 Request 对象而不是超全局变量。

④ 生态还在早期

版本 1.13,文档和案例都在积累。遇到问题可参考的资料远少于 Nginx + FPM。

什么时候选它

  • 想拿常驻内存的性能,但不想改业务代码
  • 想少运维一个组件(不需要 Nginx)
  • 单机或小规模部署,想要自动 HTTPS
  • 已经在用 Caddy

不选它的场景:需要成熟稳定的生产方案(Nginx + FPM 更保险)、需要复杂的反向代理和负载均衡(这些还是 Nginx 强)、团队不愿意试新东西。

一个务实的迁移路径

  1. 先用经典模式跑起来(frankenphp php-server),确认功能正常
  2. 压力测试对比,看 worker 模式能带来多少提升
  3. 开 worker 模式,配 MAX_REQUESTS 防内存泄漏
  4. 观察一周,没问题再替换生产环境

不要一步到位。 先用经典模式验证兼容性,是风险最低的做法。

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇