Nginx 与 PHP-FPM 调优:先定位瓶颈,再决定改哪个参数
Nginx 与 PHP-FPM 调优应先区分连接层、转发层、执行层与超时层的信号,再改参数。pm.max_children 受内存约束,FPM 终止超时与 Nginx 读取超时不应倒挂,listen.backlog 需与内核 somaxconn 匹配。每次只改一个参数,并用状态页、慢日志、stub_status 与 socket 队列留下对照。具体取值依赖版本、硬件与流量模型,本文未联网核验,也未执行压测。
- 先看 FPM 活跃进程是否已达上限,再判断是容量问题还是脚本执行慢。
- Nginx 的 fastcgi_read_timeout 若短于 FPM 的 request_terminate_tim
- 一次只改一个参数,并用同一压测条件保留改动前后的对照记录。
Nginx 与 PHP-FPM 调优最常见的失败不是某个参数写错,而是顺序错了:还不知道请求卡在哪一层,就先改 pm.max_children 或 worker_connections,改完既说不清是否变快,也无法复现。可行的顺序是先把「排队、执行、超时、内存」四类信号分开观测,再决定动哪个参数。本文讨论判定顺序与参数间的耦合关系;具体取值取决于 PHP/Nginx 版本、内存与流量模型,属于待核实项。本文未联网核验,也未执行任何压测或配置加载。
一、先确认请求卡在哪一层#
一次 PHP 请求经过三段:Nginx 接收连接、转发给 FPM、FPM 子进程执行脚本。三段各有自己的排队点。
- Nginx 连接层:
worker_connections用尽时,新连接被拒绝或排队,Nginx 错误日志会出现连接相关报错。 - 转发层:FPM 进程池无空闲 worker 时,请求进入 listen 队列等待;队列满后连接被拒。
- 执行层:脚本本身慢,如数据库查询、外部 API、磁盘 IO。此时 worker 被占住,会反过来加剧转发层的排队。
判据是:如果请求变慢的同时 FPM 活跃进程数已顶到 pm.max_children,问题在池容量或执行时长;如果活跃进程数远低于上限而响应仍慢,应先查脚本与下游依赖,而不是加进程。
二、参数之间是耦合的#
pm.max_children受内存约束。子进程数乘以单进程常驻内存后,要为系统和 Nginx 留出余量;容器环境还要对齐内存限制,否则 OOM killer 会替你“调参”。request_terminate_timeout(FPM 终止脚本)与fastcgi_read_timeout(Nginx 等待上游)不应倒挂。若 Nginx 先超时,客户端拿到 504,而 FPM 里的脚本仍在跑,形成看不见的负载。listen.backlog要与内核somaxconn匹配,单方面调大没有意义。- Nginx 到上游的
keepalive与 FPM 的pm.max_requests都会改变连接复用行为,两者同时改会掩盖各自的贡献。
三、一个可改的配置骨架(未执行示例)#
下面是结构示意,值全部为占位符,未在任何环境加载执行。
; php-fpm pool 片段(占位,未执行)
pm = dynamic
pm.max_children = ${MAX_CHILDREN}
pm.start_servers = ${START}
pm.min_spare_servers = ${MIN_SPARE}
pm.max_spare_servers = ${MAX_SPARE}
pm.max_requests = ${MAX_REQUESTS}
request_terminate_timeout = ${FPM_TIMEOUT}
request_slowlog_timeout = ${SLOW_TIMEOUT}
slowlog = /var/log/php-fpm/slow.log
pm.status_path = /fpm-status
# nginx 片段(占位,未执行)
location ~ \.php$ {
fastcgi_pass unix:/run/php-fpm.sock; # 或 127.0.0.1:9000
fastcgi_read_timeout ${NGINX_TIMEOUT}; # 建议大于 FPM_TIMEOUT
include fastcgi_params;
}
四、一次只改一个,并留下对照#
可用的观测点包括:FPM 状态页(活跃/空闲进程、队列长度)、FPM 慢日志、Nginx stub_status,以及 ss -lnt 观察 listen socket 的 Send-Q 是否持续堆积。每次只改一个参数,在同一压测条件下记录改动前后的指标;没有对照的“感觉快了”不构成结论。
五、边界条件#
- 不要照抄他人的
pm.max_children:它取决于单进程内存与业务执行时长。 static减少进程管理开销但常驻内存高;ondemand省内存但冷启动有延迟,适合低频池。- 不同大版本的默认值与可用指令存在差异,具体语义以所装版本的官方文档为准;本文未核验版本细节。
一句话收束:调优的产出不是一组“最佳参数”,而是一条能重放的判定路径——先知道瓶颈在哪,再让参数去匹配它。