

“FrankenPHP自称是 “现代PHP应用服务器”,提供了一种单进程的PHP运行解决方案。其工作模式(Worker Mode)通过减少框架初始化时间,显著提升了兼容应用的性能。
然而,并非所有应用都适合工作模式。由于应用中可能存在大量全局状态,适配工作模式并非总是简单。为了全面评估,我们将探讨FrankenPHP在“经典模式”下是否也能提升应用的性能。
在本文中,旨在验证这些结果,明确测试PHP运行时的性能,而非PHP脚本执行、Linux调度器、Web服务器或其他外部因素的影响。测试结果表明,PHP-FPM与FrankenPHP经典模式在性能和吞吐量上几乎没有差异。
与我们之前比较不同PHP版本性能的文章一致,我们使用了一台Hetzner VPS,配备8个专用vCore(AMD EPYC 7003或9004,Hetzner CCX33)。操作系统为新发布的Debian 13(“Trixie”)。
“我们将对比
FrankenPHP v1.9.1(PHP 8.4.12,Caddy v2.10.2)与nginx/1.26.3搭配PHP-FPM 8.4.11的性能。测试工具为Vegeta v12.12.0。
FrankenPHP通过推荐的curl | sh命令安装为独立二进制文件。nginx和PHP-FPM则通过Debian Trixie的官方软件源安装。
安装后,我们仅对nginx配置做小幅调整,修改端口以避免冲突,并启用Debian提供的PHP配置块。此时,FrankenPHP与nginx+PHP-FPM组合均使用默认配置,未进行性能优化。
为聚焦运行时环境的开销,而非PHP本身的性能,我们使用不含业务逻辑的简单脚本进行测试。此外,我们避免高并发测试,仅为每个CPU核心分配1个工作进程。完整的Vegeta输出(包括更多吞吐量和响应时间百分位数据)可通过下表中的“测试标签”链接查看。
一个典型的服务器端渲染HTML登陆页面大约包含50 KiB数据,我们以此作为基本测试场景:
<?php
header('content-type: text/html; charset=utf-8');
$str = str_repeat('x', 1023) . "\n";
for ($i = 0; $i < 50; $i++) {
echo $str;
}
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
在60秒的测试中,8个客户端以最大速度请求服务器,nginx+FPM组合每秒处理7023个请求(整体延迟更优),而FrankenPHP经典模式处理6934个请求(最大延迟略优)。nginx+FPM比FrankenPHP经典模式快约1.3%,但差异不足以影响实际应用。
这就完结了吗?还没。登陆页面只是应用中的一种场景。如果其他场景的结果不同呢?
我们将响应改为二进制格式,例如PDF,测试结果如下:
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
7610.31 | 5368.85 | 1.828 | 4.246 |
仅将Content-Type从text/html改为application/pdf,保持响应内容不变,FPM的性能提升(延迟更优),而FrankenPHP变慢。
<?php
header('content-type: application/pdf');
$str = str_repeat('x', 1023) . "\n";
for ($i = 0; $i < 50; $i++) {
echo $str;
}
接下来,我们测试在HTML中嵌入“加密”的Base64编码随机数据(通过随机数据模拟加密):
<?php
$random = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar());
for ($i = 0; $i < 50; $i++) {
echo $random->getBytesFromString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 1023), "\n";
}
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
7610.31 | 5368.85 | 1.828 | 4.246 | |
随机数据 | 1940.05 | 5606.22 | 7.704 | 3.143 |
FPM和FrankenPHP的性能均下降,这在意料之中,因为脚本执行了更多工作。但FrankenPHP的RPS是FPM的2.89倍,这一异常结果将在后文解释。
如果减少工作量,测试极简的“Hello World”呢?
<?php
echo "Hello World!";
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
7610.31 | 5368.85 | 1.828 | 4.246 | |
随机数据 | 1940.05 | 5606.22 | 7.704 | 3.143 |
Hello World | 18478.69 | 18403.81 | 0.904 | 0.877 |
FPM和FrankenPHP均达到约18400 RPS,差异仅0.4%,延迟表现相当。
Ivan Vulovic的文章测试了高并发场景。虽然我们认为这更多测量了操作系统调度器的性能,而非运行时本身,但FrankenPHP可能在调度器友好性上有所优化。我们以“Hello World”为例,测试高并发结果:
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
7610.31 | 5368.85 | 1.828 | 4.246 | |
随机数据 | 1940.05 | 5606.22 | 7.704 | 3.143 |
Hello World | 18478.69 | 18403.81 | 0.904 | 0.877 |
Hello World 并发100 | 21847.61 | 22675.24 | 9.742 | 23.365 |
FrankenPHP的RPS高出约3.7%,但延迟分布较差。
上述测试均基于默认配置。我们尝试了一些性能优化:
fastcgi_keep_conn。pm=static和pm.max_children=16(与FrankenPHP的num_threads匹配)。优化后,性能差异仍不明显。
PDF和随机数据场景的性能差异如何解释?显然,我们测量的不是PHP-FPM与FrankenPHP的运行时开销,而是nginx和Caddy的输出压缩实现质量。
Vegeta设置了accept-encoding: gzip请求头,nginx和FrankenPHP会在适合的情况下自动压缩PHP响应:
是否压缩 | FrankenPHP | nginx |
|---|---|---|
HTML | 是 | 是 |
否 | 否 | |
随机数据 | 是 | 是 |
Hello World | 否 | 是 |
在PDF场景中,两者均不压缩响应,nginx性能更优,而FrankenPHP处理较大响应体时表现不佳。在随机数据场景中,nginx尝试压缩不可压缩数据时性能下降,而FrankenPHP表现更好。
通过设置accept-encoding: identity禁用压缩,重新测试HTML响应:
响应类型 | FPM RPS | FrankenPHP经典模式 RPS | FPM 99% ms | FrankenPHP经典模式 99% ms |
|---|---|---|---|---|
HTML | 7023.11 | 6934.06 | 2.022 | 2.06 |
7610.31 | 5368.85 | 1.828 | 4.246 | |
随机数据 | 1940.05 | 5606.22 | 7.704 | 3.143 |
Hello World | 18478.69 | 18403.81 | 0.904 | 0.877 |
Hello World 并发100 | 21847.61 | 22675.24 | 9.742 | 23.365 |
HTML 无GZIP | 7456.47 | 5504.16 | 1.786 | 3.993 |
结果与PDF场景类似。我们还尝试用HAProxy 3.0.11替代nginx作为FastCGI网关,略微提升了RPS和延迟,但差异在实际应用中不显著。
综上,PHP-FPM与FrankenPHP经典模式在运行时开销上的差异微乎其微,不足以推荐始终切换到FrankenPHP经典模式。
与之前的基准测试一致,应用架构对性能的影响最大,没有捷径能显著提升性能。优化PHP启动时间的微秒级差异,在面对数百毫秒的数据库等待时间时无足轻重。 使用Tideways等APM工具可帮助发现应用代码中的性能瓶颈。
关于选择PHP运行时,建议根据团队熟悉度和需求决定: