用户登录

技术文章

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

Nginx 与 PHP-FPM 调优实战:把参数改动写成可复现的测量记录

一句话回答

没有基线测量时,调参无法验证。文章给出一份可复现流程:固定测量口径、用 Nginx stub_status 与 PHP-FPM status 取服务端计数、把参数与观测量对应起来、一次只改一个变量并记录回滚条件;同时说明当耗时主要在数据库、上游调用或 I/O 时,改进程类参数只会改变排队位置。文中示例未执行,具体默认值与指令需对照所用版本文档核实。

手上有一套 Nginx + PHP-FPM 服务,想知道该改哪些参数——这个问题的前提往往被跳过:若没有改动前后的可比数据,参数取值只能算猜。本文给的不是一组推荐数值,而是一份可复现的测量与改动记录流程。本次没有提供可核验的测试环境与结果,文中配置示例均未执行,仅示结构;具体指令名、默认值请对照所用 Nginx 与 PHP-FPM 版本的官方文档(待核实)。

第一步:先固定测量口径#

只有同一份流量下反复测同一个量,前后对比才有意义。以下条件在整轮实验中应保持一致,任一项变化都会让数据不可比:请求路径与参数、并发数、压测持续时间、压测客户端所在网络位置、是否经过 TLS、缓存是否开启、是否启用 opcache。

需要记录的观测量至少包括:

  • 吞吐:单位时间内成功完成的请求数;
  • 延迟分位:p50 / p95 / p99。注意分母只算完成的请求,超时请求若被剔除,会系统性高估表现;
  • 错误率与超时数,单独记录,不并入延迟统计;
  • 主机侧:CPU 使用率、负载、可用内存;
  • 进程侧:Nginx worker 数、PHP-FPM 活跃与空闲进程数、常驻内存。

第二步:让服务自己报数#

Nginx 的 stub_status 提供连接与请求计数,PHP-FPM 的 status 页提供进程池状态(活跃/空闲进程、listen queue 长度等)。两者都应限制为本地或内网访问。字段含义以所用版本文档为准。

# 未执行示例:结构示意,路径与语法请对照所用 Nginx 版本文档
location = /basic_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}
; 未执行示例:在 PHP-FPM pool 配置中启用,指令名随版本核对
pm.status_path = /fpm-status

读这些计数的用途是定位层级,而不是直接给出结论:连接被接受但未被处理的计数持续增长,通常指向连接过早断开;listen queue 长期非零,说明空闲 worker 不足以接住瞬时并发,此时应先看单请求耗时构成,而不是直接加进程。

第三步:把参数与观测量对上#

参数通常影响的观测量判断方向
worker_processesCPU 饱和度、Nginx 侧排队CPU 未饱和而排队明显,才值得调整
worker_connections并发连接上限相关错误错误随并发上升而出现,再核对该上限
keepalive_timeout连接复用率、TIME_WAIT 数量结合客户端是否复用连接判断
pm 与 pm.max_childrenlisten queue、内存占用、错误率队列非零且内存有余量时才上调
pm.max_requests进程重启频率、内存曲线内存随请求数单调上升时才有意义
request_terminate_timeout超时错误数、长请求占比依据业务最长合理耗时设定,不宜用作掩盖慢查询

第四步:一次只改一个变量#

改一个参数、用同一份压测重跑、记录数据与结论;未达预期就回滚到上一版配置。变更记录里写清"改了哪一项、观察到什么、为什么保留或回滚",比保存一份所谓最优配置更有复用价值。

什么时候调这两个组件没有用#

如果单请求耗时主要花在数据库查询、上游 HTTP 调用、磁盘 I/O 或 TLS 握手,调整 worker 数量与 pm.max_children 只会改变请求排队的位置,不改变总耗时。可行的做法是在应用侧打点拆分各阶段耗时,再与 Nginx 记录的请求耗时、上游响应耗时对照。

关于具体数值#

进程数上界可以用"可用内存 ÷ 单进程常驻内存"估算一个量级,但单进程常驻内存必须在本机测量,它随框架、扩展与 opcache 配置变化很大。本文不给具体数值,因为它取决于部署环境,且本次没有可核验数据支持任何一组取值。所有默认值请以对应版本文档为准(待核实)。

先能重复测出同一个数,再谈把数改小。参数只是可以被测量的变量之一,不是调优的起点。

作者:沐小悠

本文约 5 分钟读完 · 关键词:Nginx 调优、PHP-FPM 调优、stub_status、pm.max_children、性能基线

更多文章 GET 示例接口

「」标签下的其他文章