由于最近在看接口监控的时候发现有一些502的情况,所以打算排查下原因。看了下nginx及php-fpm日志后偶然发现报502的时间节点跟fpm重启正好吻合。确认了下这个重启只是reload的操作而非restart的操作。什么?reload不是平滑启动吗?怎么会导致这样的问题出现呢?上网查了下资料后发现也有很多人遇到过这种情况。
接下来重现下这种情况。写几行代码来实际模拟下:
sleep(10); echo "test";
然后在浏览器中访问一下,同时执行fpm reload的操作。可以看到执行完reload后页面立马就502了。
实际上通过process_control_timeout参数可以实现我们的目标。可惜这个参数缺省是 0,也就是不生效,这里把它设置成为2s。然后再重复一次上面的操作后发现页面可以正常输出test。同时会发现页面并不会等待10s后打印test。当我们 reload 的时候,sleep 立刻就结束了,这是因为 sleep 收到 reload 发出的信号后直接返回了。
process_control_timeout参数参考官网文档的解释:设置子进程接受主进程复用信号的超时时间。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。
即reload的时候,如果有正在执行的请求进程便会等待该进程设置的时长。而其他进程直接就结束掉。等待正在执行的进程执行完或者是超过了设置的时间后fpm的master进程才开始生成新的fpm worker进程。
结论
默认情况下,PHP-FPM 无法保证平滑的执行 reload 操作,必须设置一个合理的 process_control_timeout 才行,同时需要注意的是其值不能设置的过大,否则系统可能出现严重的请求堵塞问题。