本文最初写于2017年,2026年根据PHP官方文档重新整理。

PHP-FPM是FastCGI进程管理器。以Nginx和PHP的常见组合为例,Nginx接收HTTP请求,将需要PHP处理的部分通过FastCGI交给FPM;FPM管理一组worker进程,每个worker在同一时刻处理一个请求。

这个模型不复杂,但配置不当时很容易出现两种结果:worker太少,请求排队;worker太多,内存耗尽或引发更严重的资源竞争。

master与worker

FPM启动后由master进程管理pool和worker。master负责进程生命周期、配置和信号处理,worker负责执行具体的PHP请求。

不同pool可以使用不同的用户、监听地址和进程参数,从而隔离不同应用。但pool增多并不会创造额外资源,所有worker最终仍然共享机器的CPU、内存和I/O能力。

三种进程管理模式

FPM通过pm选择worker数量的管理方式。

static

始终保持pm.max_children个worker。数量固定、行为容易预估,适合流量稳定且资源预算明确的服务。

dynamic

启动时创建pm.start_servers个worker,再根据空闲进程数量,在pm.min_spare_serverspm.max_spare_serverspm.max_children约束下动态增减。

它适合有波动但仍希望保留一定预热能力的场景。

ondemand

启动时不预先创建worker,请求到来时再生成,空闲时间超过pm.process_idle_timeout后退出。它可以减少低频服务的常驻内存,但冷启动和突发流量下的进程创建成本需要纳入考虑。

如何确定worker数量

pm.max_children限制可以同时处理的请求数。它不应从网上复制一个固定值,而应结合实际观测:

  1. 测量真实业务worker的平均和高位内存占用;
  2. 为操作系统、Nginx、日志和其他服务预留内存;
  3. 用可分配给FPM的内存除以单个worker的高位占用,得到初步上限;
  4. 再通过压测和线上延迟、队列、CPU与数据库连接情况校正。

内存允许不等于下游能够承受。worker增加后,数据库连接、缓存请求和外部调用也会同时增加。

比进程数更重要的观测

实际运行中至少应该关注:

  • 活跃、空闲和总worker数量;
  • 是否频繁达到pm.max_children
  • 请求排队和响应时间;
  • 慢请求及其调用栈;
  • worker内存是否随请求持续增长。

pm.max_requests可以让worker处理一定请求后重启,对第三方库的内存泄漏具有缓解作用,但它不能替代定位泄漏原因。

FPM调优的重点并不是找到一组“最佳参数”,而是让并发能力、内存预算和下游容量保持一致,并能在达到边界之前被观察到。

参考