pm.max_children需按(可用内存×0.7)÷单进程平均rss计算并向下取整;dynamic模式下pm.start_servers设为cpu核心数×2,pm.min_spare_servers≈start_servers×0.6,pm.max_spare_servers≈max_children×0.7;pm.max_requests应设500~2000防内存泄漏,禁用0;unix socket需严格匹配nginx用户权限。

PHP-FPM 进程池参数不是调得越大越好,反而容易因内存耗尽触发 OOM Killer 或让响应变慢;关键是要根据服务器真实内存、PHP脚本平均内存占用、并发请求特征来算,而不是套用网上“50/10/5/35”这类固定值。
怎么算 pm.max_children 才不炸内存
这个值决定最多能同时跑多少个 PHP 进程,直接吃内存。硬设 50 可能刚启动就占掉 2GB+(假设每个进程均占 40MB)。更靠谱的做法是实测单个请求的内存峰值:
- 临时开启
memory_get_peak_usage(true)在关键脚本里打点,或用php -r "echo memory_get_peak_usage(true);"跑典型页面 - 用
ps aux --sort=-%mem | grep php-fpm观察运行中 worker 的 RSS 值(单位 KB),取稳定后的平均值 - 公式:
pm.max_children ≈ (可用内存 × 0.7) ÷ 单进程平均 RSS(留 30% 给系统、MySQL、Nginx 等) - 如果结果是 32.8,就取整为 32,别四舍五入——宁可稍保守
pm = dynamic 下的三个 spare 参数怎么配才不抖
这三个值控制空闲进程伸缩节奏,配不好会导致“请求一来狂拉进程,一闲全杀光”,造成延迟毛刺:
-
pm.start_servers建议设为 CPU 核心数 × 2(不是 ×4,后者在低负载时浪费资源) -
pm.min_spare_servers设为pm.start_servers × 0.6左右,保证基础水位不空转 -
pm.max_spare_servers设为pm.max_children × 0.7,避免空闲太多却不敢回收 - 如果用
pm = ondemand,必须配pm.process_idle_timeout = 10s,否则空闲进程永不退出,pm.max_children就形同虚设
pm.max_requests 设成 0 是最危险的省事做法
设为 0 表示子进程永不死,看似省事,但实际会累积内存泄漏、OPcache 失效、全局变量污染等问题,尤其在用了老旧扩展(如某些 MySQLi 封装、GD 内存管理异常)时,几小时后单个 worker RSS 可能翻倍:
- 生产环境建议设为 500~1000,具体看日志里
slowlog和error_log是否频繁出现Allowed memory size exhausted - 如果应用本身很轻量(纯 API、无大图处理),且确认无内存泄漏,可设到 2000
- 每次重启 worker 都会重载 OPcache,所以
pm.max_requests也间接影响 OPcache 命中率,别盲目拉高
Unix socket 比 TCP 快,但 listen.owner 权限错就直接 502
用 listen = /run/php/php8.2-fpm.sock 能减少 TCP 栈开销,但权限链一断,Nginx 就连不上:
- 确保
listen.owner = www-data和listen.group = www-data与 Nginx worker 进程用户一致(查ps aux | grep nginx看 user 列) -
listen.mode = 0660是安全底线,0666虽然“能连”,但等于把 socket 暴露给所有本地用户 - 路径
/run/php/是 tmpfs,重启丢失,所以不要手动mkdir后 chown,而是靠 systemd 的RuntimeDirectory=php自动创建
真正卡住人的从来不是参数名记不住,而是没意识到 pm.max_children 是内存计算器、pm.max_requests 是泄漏防火墙、listen.owner 是权限开关——它们各自失效时的症状完全不同,得分开验证,不能一起调。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











