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