php-fpm

Nginx 返回 502/504,PHP-FPM 日志出现 max_children reached 或 listen queue 满。

现象

PHP 站点间歇性 502/504,静态资源正常;Nginx error log 出现 connect() to unix:/run/php/php-fpm.sock failed (11: Resource temporarily unavailable) 或 upstream timed out。FPM 日志可能提示 server reached pm.max_children setting。

快速定位

先看 FPM 日志和进程状态,再看队列与内存预算:

journalctl -u php-fpm --since '30 min ago' --no-pager | tail -100
tail -100 /var/log/php-fpm/error.log
tail -50 /var/log/php-fpm/www-error.log
systemctl status php-fpm
ps -o pid,rss,cmd -C php-fpm

开启 status 页后读取关键字段(listen queue、active processes、max children reached、slow requests):

pm.status_path = /status
curl -s http://127.0.0.1/status?full | sed -n '1,40p'
curl -s http://127.0.0.1/status | grep -E 'active|idle|queue|max children|slow'

再看 socket 队列、系统 backlog 和内存:

ss -lntp | grep -E 'php|9000'
sysctl net.core.somaxconn
smem -t -P php-fpm
grep -E 'failed \(11|upstream timed out|no live upstreams' /var/log/nginx/error.log | tail

listen queue 持续大于 0、max listen queue 很大,说明请求在等待 worker;active processes 长期等于 pm.max_children 则是 worker 被打满。

易误判:max children reached 是累计计数器,历史大于 0 不代表当前过载,必须结合 active processes 和 listen queue 看当下。另一个坑是把各 worker 的 RSS 直接相加来算内存预算 —— opcache 和共享库会被重复计算,应使用 smem 的 PSS 或单 worker 私有内存估算。

常见根因

  1. 慢请求占满 worker:外部 API、数据库、文件锁或 sleep 把 active processes 顶到上限。
  2. pm.max_children 超过内存预算,多个 pool 叠加后触发 OOM Killer。
  3. 代码或扩展泄漏,worker RSS 持续增长,且 pm.max_requests=0 从不回收。
  4. listen.backlog 或 net.core.somaxconn 太小,Unix socket 接受队列溢出。
  5. request_terminate_timeout 与 Nginx fastcgi_read_timeout 不匹配,网关先断或 FPM 先杀。
  6. 动态 pm 的 spare 参数不合理,频繁 spawn/kill worker,增加延迟。
  7. socket 属主/权限错误,或 TCP 监听端口耗尽、防火墙拦截。
  8. rlimit_files 太小,worker 打开文件/连接失败。

修复

相关命令

读完自测

  1. FPM status 里哪些字段能证明当前请求在排队?
  2. 为什么不能把每个 worker 的 RSS 直接相加来定 pm.max_children?
  3. Nginx 报 (11: Resource temporarily unavailable) 通常对应哪一层问题?
答案
  1. listen queue 持续大于 0、max listen queue 偏高,同时 active processes 接近 pm.max_children。
  2. RSS 包含共享的 opcache 和共享库,直接相加会高估;应按 PSS 或单 worker 私有内存估算。
  3. 通常是 FPM 的 listen backlog 或系统 somaxconn 不足,接受队列溢出,而非 worker 崩溃。