线上环境 PHP-FPM 配置优化后如何平滑重载不中断服务?
核心结论:向 PHP-FPM 主进程发送 SIGUSR2 信号可实现平滑重载,旧进程处理完当前请求后自动退出,确保业务零中断,生产环境中使用 service php-fpm reload 比 systemctl restart php-fpm 更安全。
原因分析
PHP-FPM 采用 master-worker 进程架构,master 进程负责监听端口和注册信号,worker 进程负责处理具体请求。当执行 systemctl restart php-fpm 硬重启时,所有正在处理请求的 PHP 子进程会被强制杀死,导致支付、下单等关键逻辑被强行中断,可能引发 502 Bad Gateway 错误。根据 2021 年 3 月 10 日的技术资料,PHP 5.3.3 以后的 php-fpm 不再支持以前的 /usr/local/php/sbin/php-fpm (start|stop|reload) 等命令,需要使用信号控制:INT、TERM 用于退出 Fpm,USR1 用于重新加载日志文件,USR2 用于重启 Fpm。
平滑重载的实现方法
方法一:使用 SIGUSR2 信号
查找 php-fpm 主进程 ID:ps -aux | grep php-fpm,找到 master process 的进程 id。执行命令:kill -SIGUSR2 process_id 实现平滑重启。根据 2017 年 12 月 5 日的资料,修改了 php 配置后需要平滑启动 php-fpm,该过程确保服务不会中断。也可以使用 service php-fpm reload 命令,该命令底层执行 kill -USR2 `cat $php_fpm_PID`。
方法二:配置超时机制
在 php-fpm.conf 文件中设置 process_control_timeout 参数,该参数默认值为 0。根据 2018 年 7 月 14 日的测试数据,设置 process_control_timeout=10 表示最多 10 秒超时,超过设置的时间会强制重启,中断正在进行中的进程。实例测试显示,在设置 10 秒超时情况下,如果代码逻辑需要 11 秒,重启会造成代码执行部分然后退出的情况。
Nginx 与 PHP-FPM 协同配置
PHP 脚本的重载不仅仅是 PHP-FPM 的事,作为反向代理的 Nginx 也扮演着关键角色。根据酷番云知识库的实际运维案例,曾有一家电商客户反馈代码更新后,首页商品价格始终不变,经排查发现是 Nginx 配置了过长的 fastcgi_cache_valid 时间。解决方案是在 PHP 脚本重载或代码更新时,同步清理 Nginx 的 FastCGI 缓存目录,或者通过配置 Cache-Control 头让 Nginx 动态判断缓存。Nginx 使用 nginx -s reload 可快速完成重新加载配置操作,reload 时旧的 worker 进程和新的 worker 进程共存,旧的 worker 进程在处理完请求后会被杀掉。
高负载场景优化建议
根据 2020 年 11 月 27 日的资料,针对 Nginx 出现 502 错误时的解决方案包括:1. 在 php-fpm.conf 里增加 max_children 的值,建议值因服务器性能而异,4GB 内存的服务器上 200 就可以,1G 测试机开 64 个是最好的;2. 用 crontab 定时重载 php-fpm,命令:*/10 * * * * /usr/local/php/sbin/php-fpm reload;3. 调高 Linux 内核打开文件数量:echo 'ulimit -HSn 65536' >> /etc/profile;4. 增加 PHP-FPM open file description rlimit,将 1024 改为 4096 或更高数字。
注意事项
1. 进程信号差异:给 php-fpm 发送重启信号 kill -USR2 pid,这个 pid 既可以是 master 进程的 pid,也可以是 worker 进程的 pid,如果是 master 进程的 pid 就会把所有 worker 进程重启,如果是 worker 进程的 pid 就是只重启单个 worker 进程(2018 年 7 月 14 日资料)。
2. 未完成请求处理:发送重启信号后,master 获取 event 然后给 worker 进程发送退出信号 SIGQUIT,worker 进程接收信号后将 in_shutdown 变量置为 1,如果进程还没有执行结束也会退出,可能出现代码逻辑执行一半的情况(2018 年 7 月 14 日资料)。
3. 版本兼容性:PHP 5.3.2 以后的版本不支持以前的 php-fpm (start|restart|stop|reload),需要将 php-fpm 配置成服务并添加平滑启动/重启,配置 php-fpm.conf 时将 pid 前的;去掉(2021 年 3 月 18 日资料)。
4. 缓存问题:即使 PHP 脚本重载成功,客户端依然可能获取到旧的页面内容,需同步清理 Nginx 的 FastCGI 缓存目录。
参考来源
来源:酷番云知识库 - PHP 脚本如何重载服务器?服务器重载配置方法详解
来源:CSDN 技术社区 - php 平滑重启(2017 年 12 月 5 日)
来源:博客园 - php fpm 平滑启动,php-fpm 平滑启动并配置服务(2021 年 3 月 18 日)
来源:腾讯云开发者社区 - fpm 平滑重启_PHP-FPM 高负载的解决办法(2020 年 11 月 27 日)