起步
在测试中,发现 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-fpm
是 master 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 排队,并在从新加载实现后立刻执行。最终用户的后果是,在此期间,他们看到浏览器显示加载中。另一点是设置的超时,也不能保障申请在这个工夫内解决完,还是须要程序员保障本人的脚本运行工夫在正当范畴内。