乐趣区

关于php:关于-phpfpm-reload-会取消正在处理的请求的解决方案

起步

在测试中,发现 php-fpm reload 会强制 kill 掉正在解决的申请。网上查了一下,发现其他人也有这个问题并反馈给了官网:https://bugs.php.net/bug.php?id=75440 和 https://bugs.php.net/bug.php?id=60961,帖子是 2017 和 2012 年的,到当初还没解决。

官网帮忙手册还说 reload 是 graceful,啊哈哈,不要太置信:

man php-fpm
...
SIGINT,SIGTERM
    immediate termination
    SIGQUIT 
graceful stop
    SIGUSR1 
re-open log file
SIGUSR2
    graceful reload of all workers + reload of fpm conf/binary
...

reload 流程简介

php-fpmmaster worker 的工作形式。

php-fpm master 过程通过承受用户发送的 SIGUSR2 信号实现本身服务的 reload:

kill -USR2 <pid>

主过程(master 过程)收到 reload 信号,会向所有子过程发送 SIGGUIT 信号,同时注册定时器工夫,timeout 的值为 fpm_global_config.process_control_timeout。在规定工夫之内子过程还没有完结,则子过程将被 kill。比方 timeout 值设为 1 秒,如果在 1 秒之内还没有完结,则间接向子过程发送 SIGKILL 信号,强制杀死。

最初 master 期待所有的子过程完结后,依据之前保留的启动参数重新启动一个过程,并继承父过程的 socket 文件描述符。

金蝉脱壳

留神,这只是缓解的计划,仍然不能保障申请不会失落。这个计划在于 process_control_timeout 这个配置选项,配置文件在 php-fpm.conf (我的是在 /usr/local/etc/php-fpm.conf) 中,默认值是 0,会立刻将子过程 kill 掉,这里我改为了 60s 进行测试:

; Time limit for child processes to wait for a reaction on signals from master.
; Available units: s(econds), m(inutes), h(ours), or d(ays)
; Default Unit: seconds
; Default Value: 0
process_control_timeout = 60s

测试后果,正在解决的申请只有在该工夫内实现申请,就能失常返回。

这不是 100% 的计划是因为,master 过程要期待所有子过程完结才会从新创立 worker 过程,而 process_control_timeout 期待的时候,worker 过程不承受申请了,因而这段时间内新的申请进不来,这些新申请将由 fpm 排队,nginx 若超时会报 502 给用户,保险起见,nginx 的超时工夫的值应该是 process_control_timeout 的两倍。

只管可能会报 502,但这样的解决形式比杀死正在解决的申请让人承受的多了。

总结

只管设置了 process_control_timeout,在上述情况之上,PHP-FPM 在 reload 实现之前不会为新申请提供服务。然而,所有这些新申请将由 fpm 排队,并在从新加载实现后立刻执行。最终用户的后果是,在此期间,他们看到浏览器显示加载中。另一点是设置的超时,也不能保障申请在这个工夫内解决完,还是须要程序员保障本人的脚本运行工夫在正当范畴内。

退出移动版