本文最初写于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_servers、pm.max_spare_servers和pm.max_children约束下动态增减。
它适合有波动但仍希望保留一定预热能力的场景。
ondemand
启动时不预先创建worker,请求到来时再生成,空闲时间超过pm.process_idle_timeout后退出。它可以减少低频服务的常驻内存,但冷启动和突发流量下的进程创建成本需要纳入考虑。
如何确定worker数量
pm.max_children限制可以同时处理的请求数。它不应从网上复制一个固定值,而应结合实际观测:
- 测量真实业务worker的平均和高位内存占用;
- 为操作系统、Nginx、日志和其他服务预留内存;
- 用可分配给FPM的内存除以单个worker的高位占用,得到初步上限;
- 再通过压测和线上延迟、队列、CPU与数据库连接情况校正。
内存允许不等于下游能够承受。worker增加后,数据库连接、缓存请求和外部调用也会同时增加。
比进程数更重要的观测
实际运行中至少应该关注:
- 活跃、空闲和总worker数量;
- 是否频繁达到
pm.max_children; - 请求排队和响应时间;
- 慢请求及其调用栈;
- worker内存是否随请求持续增长。
pm.max_requests可以让worker处理一定请求后重启,对第三方库的内存泄漏具有缓解作用,但它不能替代定位泄漏原因。
FPM调优的重点并不是找到一组“最佳参数”,而是让并发能力、内存预算和下游容量保持一致,并能在达到边界之前被观察到。