记录一下那天晚上的排查过程。CentOS 7.9 + nginx 1.18 + PHP-FPM 7.2,报表导出接口原来十秒就超时,运维把 fastcgi_read_timeout 从 60s 提到 300s,结果五零二从每天几条涨到几百条,php-fpm 日志里全是 child exited on signal 9。

刚开始盯着「内存打到上限时 OOM killer 挑占用最大的进程杀,被杀的正是在跑大报表的那个」,折腾了半个多小时,排掉了。

把日志和配置对完,能解释这个现象的基本就这几处。超时放宽后慢请求长期占着子进程,进程池被塞满,后来的请求连排队机会都没有。也可能是pm.max_requests 设了 500,子进程到数就退出,nginx 复用旧连接时对端已经不在了。

还有一种情况,上游 backlog 排队超过内核上限,新连接直接被复位,日志里只留下连接被拒。

先确认子进程是主动退出还是被内核杀

grep -E 'exited on signal|max_requests' /var/log/php-fpm/error.log | tail -20

再往下看内核有没有留下击杀记录

dmesg -T | grep -i 'killed process' | tail -5

然后核对进程池与超时的当前取值

grep -E 'pm.max_children|pm.max_requests|request_terminate_timeout' /etc/php-fpm.d/www.conf

剩下的就是把前端超时收到略大于后端,避免堆连接

sed -i 's/fastcgi_read_timeout.*/fastcgi_read_timeout 90s;/' /etc/nginx/conf.d/export.conf && nginx -t && nginx -s reload

改完先别撤,确认这几项。跑一小时导出任务,进程池活跃数不再顶到 pm.max_children,nginx 日志里五零二归零,dmesg 也没有新的 killed process。

超时要跟进程池大小和内存一起算,单加超时等于把排队时间换成五零二和 OOM。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189