发布脚本用的是 systemctl reload php-fpm,跑了两三天后 8G 的机器内存见底,ps 里 php-fpm 进程数从二十个涨到九十个,还有几个进程的启动时间是三天前。

一开始怀疑是「有请求阻塞在外部接口的 read 上,信号送进去也不响应」,查了一圈,方向不对。

真正麻烦的地方在于,几个原因的现象几乎一样。老 worker 要等手上的请求结束才退出,长请求一直不结束它就一直不走。少数情况下是process_control_timeout 太短或没配,优雅退出没等到超时就僵在那里。

不容易想到的是,发布脚本只 reload 不检查,旧进程没人发现,几次叠加就成倍增长。

动手时先按启动时间把老进程挑出来

ps -eo pid,lstart,etime,cmd -C php-fpm --no-headers | sort -k6,7 | head

再往下看进程数相对基准涨了多少

ps --no-headers -C php-fpm | wc -l

接着把优雅退出的超时写进配置

sed -i 's/^;*process_control_timeout.*/process_control_timeout = 10s/' /etc/php-fpm.d/www.conf && systemctl restart php-fpm

等前面都确认过,再把残留的旧进程清掉

ps -eo pid,etime,cmd --no-headers -C php-fpm | awk '$2 ~ /-/ {print $1}' | xargs -r kill -TERM

改完先别撤,确认这几项。进程数回到与 pm.max_children 匹配的范围,ps 里不再有存活超过一天的 worker,free 的可用内存回升到一半以上。

reload 虽然平滑但会留下旧进程,发布后要主动核对进程数和启动时间,长期不管就是慢性内存泄漏的样子。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189