用户登录

技术文章

外部链接将在新标签页打开。

Nginx 与 PHP-FPM 调优实战:从 502、499 与排队现象反推问题层

一句话回答

调优的起点是先判断请求卡在连接层、PHP-FPM 进程池还是应用下游,再每次只改一个参数并用同一时间窗口对照验证;本文不含实测数据与推荐数值,参数取值需按自身环境核实。

Nginx 与 PHP-FPM 调优最常见的做法,是直接抄一组 worker_processes 和 pm.max_children 的数值。这些数值是否合适,取决于机器内存、单请求常驻内存、流量形态与下游耗时,通用数字必须在自己的环境里复现才有意义。本文没有可核验的测试记录,也未运行任何压测,因此不给性能数字,也不给“最优参数”;只提供一套分层定位方法:先确认请求卡在哪一层排队,再决定改什么。

一个 PHP 请求至少经过三段排队#

  • 连接层:Nginx 接收连接、完成 TLS 握手、等待空闲 worker 处理,受 worker 进程数与连接数上限约束。
  • 进程池:请求被转发给 PHP-FPM 后,等待一个空闲 worker 进程。这里排队,改 Nginx 参数通常无效。
  • 下游:PHP 进程内访问数据库、缓存或外部 HTTP 接口,耗时计入上游响应时间,与前两层无关。

先打开两个状态入口#

定位的前提是能看到排队情况。下面是示意配置,未在本环境执行,指令拼写与模块可用性请对照所使用版本的官方文档核实,路径与访问控制按实际部署调整。

# Nginx:示意配置,未执行
location = /status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}
; php-fpm pool 配置:示意,未执行
pm.status_path = /fpm-status

同时在 Nginx 的访问日志格式里保留 $request_time 与 $upstream_response_time,这两个值是后面区分层次的主要依据。

用三类信号判断层,而不是猜#

信号位置判读方向
reading / writing / waiting 连接数Nginx stub_statuswaiting 偏高通常对应 keepalive 空闲连接,需结合并发与流量形态看,单独一个数字不构成结论。
listen queue、active processes、max children reachedPHP-FPM status队列持续非零且 reached 计数增长,说明请求在进程池排队,此时应先查进程池与单请求耗时。
$request_time 与 $upstream_response_time 的差值Nginx 访问日志两者接近说明时间花在 FPM 及其下游;差值大说明时间花在 Nginx 侧、客户端侧或响应传输上。

表中不列阈值:什么算“偏高”,取决于业务可接受的延迟与机器余量,需要自己用同一时间窗口的对照数据确定。

两个容易走错方向的现场#

出现 502 就加 worker_processes

502 表示 Nginx 没能从上游拿到有效响应。若 FPM status 里同时看到队列堆积或 reached 增长,瓶颈在进程池,加 Nginx worker 只会让更多请求更快地涌向已经排满的进程池。反过来,若队列为空而 502 仍出现,才需要看 FPM 是否在重启、socket 是否可达。

把 499 当成服务端错误

499 是 Nginx 记录“客户端在响应返回前关闭连接”的状态码,反映的是总时长超出了客户端或调用方的等待预算。它指向缩短端到端耗时或重新核对超时设置,而不是简单增加进程数。

一次只改一个参数,并留下对照窗口#

  1. 固定观测范围:同一路径、同一时长窗口、同一流量水平。
  2. 记录改动前后的 p95 延迟、5xx 与 499 计数、FPM 队列峰值、CPU 与内存占用。
  3. 一次只动一个参数,改动后至少跑满一个完整窗口再比较。
  4. 没有对照窗口的改动不算验证,只能算尝试。

如果 PHP 代码里还会同步调用外部 HTTP 接口(例如通过 API.PLUS 这类第三方服务),这段耗时同样计入 $upstream_response_time。此时调 Nginx 或 FPM 参数不会缩短它,需要单独测量外部调用的耗时分布。

边界与待核实项#

  • OPcache 是否启用、静态资源是否由 Nginx 直接返回、FPM 的进程管理方式选 static 还是 dynamic,都会改变上述信号的解读,需按自身流量形态核实。
  • 各参数的具体取值、以及本文方法在当前版本上的适用性,均待核实;本文未执行任何测试,不提供性能结论。

可复用的结论只有一条:先让“哪一层在排队”有观测依据,再让每一次改动都能被同一窗口的数据支持或否定。参数表可以后补,归因链条断掉之后,调优就退化成反复试错。

作者:沐小悠

本文约 5 分钟读完 · 关键词:Nginx、PHP-FPM、性能调优、stub_status、FPM status

更多文章 GET 示例接口

「」标签下的其他文章