17611538698
webmaster@21cto.com

FrankenPHP vs PHP-FPM:哪个是赢家?

编程语言 0 33 14小时前
图片

导读:PHP8的新技术FrankenPHP有什么好的?本文详细告诉你。

我一直对追随新技术潮流持谨慎态度——尤其是在涉及 PHP 服务这类基础技术时。我认为稳定性比炒作更重要,比如多年来,Nginx 背后的 PHP-FPM一直是行业标准。

但是它并非完美无缺,但也算是久经考验。

坦白讲,我关注FrankenPHP的开发已经有一段时间,但从未真正将其视为一个可用于生产的替代方案。它看起来很有前景,但还很年轻——有点太过实验性,不适合在实际应用中冒险。

然而,这种情况最近发生了变化。

就在两个多月前FrankenPHP 获得了 PHP 基金会的官方支持,这迅速提升了它的可信任度。这种认可实属罕见,它传递了一个明确的信息:FrankenPHP 不再只是一个实验性的有趣项目——它是未来 PHP 服务模式的有力候选者。

所以,我决定是时候真正尝试一下了。

什么是 FrankenPHP

FrankenPHP是一个现代的 PHP 应用服务器和 HTTP 服务器,它们都捆绑在一个二进制文件中。它基于Caddy构建,直接在服务器进程内运行 PHP 代码,从而无需:

  • FastCGI
  • PHP-FPM
  • 反向代理服务器,例如 Nginx 或 Apache


从本质上来讲:

  • FrankenPHP = HTTP + PHP,再无需中间代理。


如果对你来说,这听起来也很熟悉,那是因为它反映了Node.js 的事件循环驱动的简单性,其中相同的过程处理 HTTP 和应用程序逻辑,再无需外部协调。

这种架构通过消除服务 PHP 页面所需的传统多进程管道,大大简化了部署并提高了系统性能。

图片

我到底在比较什么?


在此基准测试中,我比较了以下两种设置:

  • FrankenPHP,使用其内置的 HTTP 服务器(基于 Caddy)
  • Nginx + PHP-FPM,经典技术堆栈


两者都运行相同的极简文件,并在隔离的 Docker 容器中的index.php,使用PHP 8.4 。

为确保公平,使用极其简洁的环境:

  • 测试在专用 AWS EC2 实例上执行
  • 规格:6 个 vCPU 和 4 GB RAM

     以上所有基准测试均直接在实例内部运行,避免了网络延迟或本地硬件干扰

重点是衡量如下指标:

  • 吞吐量(每秒请求数)
  • 延迟(包括 p95)
  • 使用虚拟用户进行真实世界模拟


PHP 代码


为了保持公平并纯粹关注服务器性能,两个技术堆栈我们都配置为提供相同的最小 PHP 文件:

 echo "向你的问候 " . ( $_SERVER 'SERVER_SOFTWARE' ] ?? '未知服务器' );

没有使用框架,没有数据库,没有其它文件操作,只是一个简单的echo。我的想法是,在不受任何外部变量干扰的情况下,对每个服务器堆栈如何处理原始 PHP 执行进行基准测试。

用于基准测试的工具


为了使测试公平且富有洞察力,我使用了三种工具:

  • wrk — 用于测量原始吞吐量(每秒请求数)。
  • wrk2 — 用于测试恒定负载下的延迟。这有助于模拟高压环境。
  • k6 — 用于模拟真实世界的使用情况,多个虚拟用户并行发出请求。


每种工具都有其特殊的作用:

  • wrk用于将服务器推向极限——就像在健身房进行压力测试一样。
  • wrk2模拟了固定速率的稳定交通流,展示了每种设置如何处理压力而不弯曲。
  • k6模拟你的服务器在典型工作日所经历的情况——真实用户浏览、点击,偶尔刷新过多。


所有测试都重复了几次,以消除异常并建立稳定的比较基线。

wrk结果 – 负载中的最大吞吐量

为了对这两种设置进行压力测试,我使用了wrk一款高性能 HTTP 基准测试工具,它旨在模拟流量泛滥的情况,并衡量服务器的承受能力。你可以把它想象成后端的跑步机——看看它在崩溃前能跑多快。

使用的命令:

wrk -t4 -c100 -d10s http://localhost:PORT

  • -t4= 4 个线程
  • -c100= 100 个同时连接
  • -d10s= 运行 10 秒


这里的目标很简单:在稳定、密集的请求流下将两台服务器推至其吞吐量的极限。

FrankenPHP每秒发出约15,000 个请求,而 PHP-FPM 则徘徊在4,000 个以下。延迟也说明了同样的情况——FrankenPHP平均响应时间为 15 毫秒,而 PHP-FPM 则需要近30 毫秒

图片

很简单:FrankenPHP直接在 HTTP 服务器进程内运行 PHP ,中间无需 FastCGI 切换或者 Nginx。这意味着更少的上下文切换、更低的开销和更快的响应时间,特别是在高负载的情况下。

为了消除一次性峰值或 CPU 卡顿,我多次运行每个基准测试,并使用了不同的线程/连接配置(例如-t2 -c50-t6 -c200。虽然绝对值略有不同,但性能差距始终保持一致:FrankenPHP 始终“遥遥领先”。

wrk2结果——如何应对压力

如果wrk说性能是关键,wrk2那么控制力就是关键。与其让工具发送尽可能多的请求,不如wrk2保持固定的速率(比如每秒 5000 个请求),并观察服务器的响应情况。这是在可预测的持续负载下测量延迟的好方法

这是我使用的命令:

wrk2 -t4 -c100 -d10s -R 5000 http://localhost:PORT

就是这样:

  • 4个线程
  • 100 个开放连接
  • 持续10秒
  • 每秒5000 个请求,准确


现在事情变得戏剧化起来。


PHP-FPM 现在无法跟上了,它不仅无法优雅地处理每秒 5000 个请求,反而卡住了——每个请求的延迟飙升至超过一秒。有些请求甚至完全停滞,或者达到了内部限制。它根本无法跟上这种速度。


为了直观地展示这一点,这里有一个图表,比较了两种设置如何处理每秒 5000 个稳定请求流:

图片

你可以清楚地看到:

  • PHP-FPM 只能处理 5000 个请求中的约 3790 个,并且延迟极高(平均超过 860 毫秒)。
  • FrankenPHP几乎可以处理所有 5000 个请求,平均延迟仅为1.4 毫秒。不是 1 秒,而是1 毫秒。1 毫秒哦!!!

我多次运行这个程序并调整了速率,只是想看看结果是否只是巧合。结果并非如此。数字可能会略有变化,但规律始终如一:FrankenPHP 保持领先。PHP-FPM 则不堪重负。

k6 结果 — 现实检验

上次我运行的测试使用的是k6,它注重真实的流量模式,而不是暴力破解。可以把它想象成把你的应用放在一个模拟环境中——一百个虚拟用户正在做一些正常的事情,比如打开你的网站或刷新仪表盘。

在这种情况下,我模拟了:

  • 100 个虚拟用户 (VU)
  • 每 0.1 秒发出一次请求
  • 时长:10秒

结果如何呢?
图片

即使在正常流量情况下:

  • PHP-FPM平均每个请求耗时 2.56 毫秒第 95 个百分位达到近6 毫秒
  • FrankenPHP始终保持在平均 2ms以下,在 p(95) 时保持在 3.5ms 以下


它不像压力测试那样有显著的差异——但这正是关键所在。即使在“正常”情况下,FrankenPHP 仍然更敏捷、更一致,并且易于扩展。

我还多次重复了这项测试,尝试了一些细微的调整——稍微增加或减少请求间隔,调整连接池大小,甚至在不同时间运行同一项测试以考虑机器上的背景噪音。结果如何?数值略有变化,但规律保持不变:FrankenPHP 始终领先,无论是在延迟方面,还是在压力下的稳定性方面。

那么,你应该转换吗?

如果你正在构建 API、微服务或任何类型的无状态服务,并且原始性能和简单性很重要,那么 FrankenPHP 绝对值得一试。

它速度更快,使用更少的组件,而且在我运行的每一个测试中,它处理负载的能力都比 PHP-FPM 更好。尤其是在高并发或高压力的场景下,它的优势更加不容忽视。

话虽如此,但并非每个项目都已经做好准备。

如果你正在运行一个复杂的遗留应用程序,该应用程序拥有经过精心调优的 PHP-FPM 连接池,并且多年的系统管理员知识已融入到你的基础架构中,那么一夜之间跳转是一个糟糕的主意。

但是,如果你正在尝试一些新事物或者只是出于好奇心,FrankenPHP绝对适用于开发和预发布环境,甚至在很多情况下可以用于生产环境。

以下,来看我的详细解释:

  • 新项目:从 FrankenPHP 开始,以后你可能会省去一些复杂的麻烦。
  • ✅ API 和轻量级服务:FrankenPHP 在这方面表现突出。它精简且快速。
  • 🟡中型整体式架构:值得测试,特别是如果您计划进行任何基础设施更新。
  • 大型遗留应用程序:目前坚持使用 PHP-FPM ,或者进行一些认真的迁移规划。


结语


FrankenPHP 不仅速度快,而且非常现代化

对我来说,感觉 PHP 进入了单进程服务器时代,而这一转变本身就为更清洁的部署、更简单的 Docker 设置,以及我们过去只与 Node、Go 或 Rust 相关的新开发模式打开了一扇大门。

当然,FrankenPHP还很年轻,但它发展迅速,你知道它得到了 PHP 基金会的强大支持。

FrankenPHP 不仅仅是真实的性能,而且它已经准备好了

另外,如果你想探索或重现基准测试,我已将整个设置(包括 Docker 配置、脚本和测试文件)推送到了以下地址:

👉 https://github.com/Gramzivi/frankenphp-vs-nginx

作者:洛逸

评论