一、问题
今天修改了fpm一些配置,需要上线重启fpm,但是发现一瞬间出现很多502的错误请求,查看日志发现以下错误
fpm:重启日志
nginx:错误日志
2023/04/23 15:19:00 [error] 9#0: *1893053661 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: *****, server: ***.com
2023/04/23 15:19:00 [error] 9#0: *1893053661 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: *****, server: ***.com
二、原因
通过排查,最后发现:在重新加载配置文件期间,PHP-FPM master 进程会关闭所有已有的子进程,重新创建新的子进程并加载新的配置文件。在这个过程中,如果有客户端发出请求,请求就会失败并返回 502 错误。
测试案例:
<?php
echo "测试开始";
sleep(10);
echo "测试结束";
进行访问,然后在访问中, 进行 kill -USR2 maserid,页面就会出现502
三、解决方案
-
逐步平滑重启:使用
kill -USR2
命令时,可以使用php-fpm -t
命令测试新配置是否正确,然后使用kill -WINCH
命令逐步平滑重启 PHP-FPM,以避免一瞬间关闭所有子进程造成的服务中断。 -
配置进程平滑重启:在 PHP-FPM 配置文件中,你可以设置
process_control_timeout
参数,以控制每个子进程退出的最大时间。在重新加载配置文件时,master 进程会等待所有子进程在这个时间内优雅地关闭,避免服务中断。(这种方法在一篇向官方反馈的bug中也有提到,其中建议是[2013-02-13 15:57 UTC] phpbugs at oops dot mooo dot com Try setting process_control_timeout to something higher than 0. 但是切记process_control_timeout配置并不是所有php版本都支持,使用前一定要测试自己的php版本是否支持该配置,目前一般都是7.2以上才支持
)process_control_timeout = 20s ;process_control_timeout 设置子进程接受主进程复用信号的超时时间。可用单位:s(秒)、m(分)、h(小时)或者 d(天)。默认单位:s(秒)。参数缺省是 0。 即reload的时候,如果有正在执行的请求进程便会等待该进程设置的时长。而其他进程直接就结束掉。等待正在执行的进程执行完或者是超过了设置的时间后fpm的master进程才开始生成新的fpm worker进程。
-
使用进程管理工具:使用进程管理工具,如 Supervisor、Systemd、Upstart 等,来启动和管理 PHP-FPM 进程,可以更好地控制进程的生命周期和平滑重启,从而减少服务中断的风险。
总之,在重新加载 PHP-FPM 配置文件时,需要考虑到服务中断的可能性,采取适当的措施来减少风险,并尽可能地保证服务的可用性。