PHP-FPM 通过 pm 指令控制子进程生命周期:
pm.max_children 个进程,常驻内存,不增不减。pm.start_servers 个,根据负载在 pm.min_spare_servers 与 pm.max_spare_servers 间动态伸缩。pm.process_idle_timeout 后退出。| 维度 | static | dynamic | ondemand |
|---|---|---|---|
| 内存占用 | 固定,峰值 = 平均 × max_children | 波动,峰值 ≤ static | 最低,按需分配 |
| 冷启动延迟 | 无 (进程已就绪) | 低 (预热 start_servers) | 高 (首请求需 fork) |
| CPU 抖动 | 无 | 中 (频繁 fork/exit) | 高 (突发流量大量 fork) |
| 内存泄漏风险 | 高 (长期运行累积) | 中 (进程周期性回收) | 低 (进程寿命短) |
| 适用场景 | 高并发、专用服务器、内存充裕 | 通用 Web、流量波动、共享主机 | 低流量、内存受限、多站点共存 |
PHP 请求结束后,进程不退出,而是循环等待下一请求。长期运行会累积:
dynamic 模式下,空闲进程超过 max_spare_servers 会被主动杀掉,新进程干净启动,自然释放泄漏内存。配合 pm.max_requests = 500 强制周期性重生,双重保险。
START
│
├─ 服务器内存 ≥ 4GB 且 专用运行 PHP? → YES → static
│
├─ 流量平稳、高并发 (QPS > 100)? → YES → static
│
├─ 内存 ≤ 1GB 或 多站点共享? → YES → ondemand
│
└─ 其他通用场景 → dynamic
pm = static pm.max_children = 120 pm.max_requests = 1000 request_terminate_timeout = 30s
pm = dynamic pm.max_children = 80 pm.start_servers = 15 pm.min_spare_servers = 10 pm.max_spare_servers = 40 pm.max_requests = 500
pm = ondemand pm.max_children = 30 pm.process_idle_timeout = 10s pm.max_requests = 200
# 1. 观察进程数波动
watch -n 1 'ps aux | grep php-fpm | grep -v grep | wc -l'
# 2. 查看状态页面 (需配置 pm.status_path)
curl https://127.0.0.1/php-fpm-status?full&json | jq '.processes[] | {pid, state, requests, memory}'
# 3. 关键告警阈值
# - max children reached > 0/分钟 → 增大 max_children 或改 static
# - listen queue > 0 → 进程不足,请求排队
# - 进程内存 > 单进程预期 2倍 → 检查泄漏,减小 max_requests
为不同类型流量创建独立 pool:
; www.conf - 主站动态 [www] pm = dynamic ... ; api.conf - API 静态高并发 [api] listen = 127.0.0.1:9001 pm = static pm.max_children = 100 ... ; admin.conf - 后台低频 ondemand [admin] listen = 127.0.0.1:9002 pm = ondemand pm.max_children = 10 ...
Nginx 按 location 分发:fastcgi_pass 127.0.0.1:9001;
没有银弹,只有权衡。static 换稳定,dynamic 换弹性,ondemand 换节约。生产环境建议:核心业务 static + 监控告警,边缘业务 dynamic/ondemand。务必配合 pm.max_requests、慢日志、状态页面,建立观测体系,让数据说话。