Nginx 与 PHP-FPM 性能调优:先定位瓶颈,再改参数
一句话回答
调优的起点是确认瓶颈落在连接层还是进程层,而不是套用一组固定参数。Nginx 侧关注连接数上限、缓冲与上游复用,PHP-FPM 侧关注进程模型、子进程上限与超时链对齐;具体取值须由目标环境的压测与运行时指标确定,本文未执行任何压测或线上观测,不提供性能数字。
不存在一组可以跨环境复用的“最佳参数”。能复用的是一个顺序:先确认瓶颈在连接层还是进程层,再只改一个参数,最后用同一口径复核。本文给出参数含义、判定条件与定位顺序,不含性能数字。
本文的边界#
本次没有可用的正文素材,也没有执行压测或线上观测,因此不提供推荐数值、对比结果或“调优后提升多少”的结论。下文涉及的参数行为以你所装版本的官方文档为准,具体默认值与可用选项待核实。所有示例均为未执行的示例,只示意写法,数值为占位。
先分清两段:连接层与进程层#
Nginx 处理连接、TLS、静态资源与转发,PHP-FPM 是 FastCGI 进程池。同一个“变慢”可能来自 PHP 执行、进程池排队、连接建立或客户端本身。只盯 CPU 使用率容易把排队位置判断错。
Nginx 侧要看的几项
worker_processes:决定 worker 数量,通常与可用 CPU 相关;是否自动取值取决于你的版本,待核实。worker_connections:单个 worker 的连接总数上限。反向代理场景下,与客户端的连接和与上游的连接都要占用名额,因此它不是“能接多少客户端”的直接数字。- 缓冲区大小:请求头、响应体的缓冲区调大可以少写临时文件,但会按并发数放大内存占用,不是单向收益。
- 上游
keepalive:让 Nginx 复用与上游的连接,减少反复建连;是否支持及写法随版本不同,待核实。
PHP-FPM 侧要看的几项
pm:static固定进程数,dynamic按负载增减,ondemand空闲时回收。选择取决于流量是否平稳,而不是哪个“更快”。pm.max_children:子进程硬上限。打满后新请求进入排队等待,表现为延迟上升或网关超时,这是进程池机理,不是故障证据。- 超时链:
request_terminate_timeout与 Nginx 的fastcgi_read_timeout谁先触发,决定了超时后后端是否还在继续执行。两者需要按同一意图排序。
# 未执行示例:仅示意参数位置,数值为占位,不可直接用于生产
upstream php_backend {
server unix:/run/php/php-fpm.sock;
keepalive 待定; # 需按版本确认是否支持
}
; 未执行示例:pool 配置片段,数值为占位
pm = dynamic
pm.max_children = 待定 ; 先按可用内存与单进程常驻内存估算,再用压测复核
request_terminate_timeout = 待定
一个可复核的单变量流程#
- 固定压测入口、请求类型和并发档位,记录一组基线指标。
- 根据观测提出一个假设,例如“瓶颈在进程池排队”。
- 一次只改一个参数,其余保持不动。
- 用同样的入口和口径复测,比较差异是否超出波动范围。
- 保留回滚方式,再进入下一个假设。
容易越界的三个地方#
- 按内存估算子进程上限只是起点。用可用内存除以单进程常驻内存得到的是粗估,需以实际进程内存分布复核;单请求峰值内存与均值差别大时,粗估偏乐观。
- 慢日志本身有开销。开启慢请求日志能定位长尾,但阈值设得过低会带来持续的写入负担,定位结束后应重新评估是否保留。
- 缓冲区不是越大越好。放大单个连接的缓冲会按并发数放大总内存,收益与代价要在同一压测里一起看。
什么时候不该继续调参数#
如果单请求耗时主要消耗在数据库查询或外部接口调用上,调整 Nginx 与 PHP-FPM 只会改变排队发生的位置,不会缩短真正的处理时间。此时应先把外部依赖的耗时拆出来,再决定是否回到参数层。