商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 【重点解析】Swoole 如何实现平滑重启面试题

【重点解析】Swoole 如何实现平滑重启面试题

  发布于2026-07-15 阅读(0)

扫一扫,手机访问

平滑重启这事儿,听起来简单,但实际操作中不少人栽了跟头。它可不是主进程发个信号就完事了,而是需要逐一向worker进程发出通知,等它们处理完当前请求再优雅退出,然后新worker加载更新后的代码接替上岗。这里有个关键前提:你的业务代码必须在onWorkerStart回调里加载,否则改了也是白改,信号发过去根本没反应。

平滑重启不是“发个信号就完事”,而是主进程逐个通知 worker 处理完当前请求再退出,新 worker 加载新代码接替——前提是你的业务代码必须在 onWorkerStart 之后加载,否则改了也白改。

为什么 kill -USR1 有时不生效?

这个问题问得最多。常见场景是:改了代码,发个kill -USR1 $pid,结果日志没刷新,onWorkerStart没重跑,旧逻辑还在那里坚挺地执行。问题出在哪?

  • 根本原因:被修改的 PHP 文件在 server 启动之前(全局作用域)就已经被 requireinclude 了,而 Swoole 的 reload 机制不会重新加载这些文件。
  • 正确做法:所有业务类、配置、数据库连接等,必须延迟到 onWorkerStart 回调里加载或初始化,这样每次 worker 重启时才会重新执行。
  • 验证方式:在 onWorkerStart 中加一句 echo "worker {$workerId} start at " . date('Y-m-d H:i:s') . "\n";,发信号后看输出时间戳是否更新,一目了然。
  • 还要注意 opcache.enable:如果开启了,需要配合 opcache_invalidate() 或者干脆禁用 opcache,否则 PHP 缓存的字节码不会跟着文件变动而更新。

reload_async 和 max_wait_time 怎么配才不丢请求?

这两个参数直接影响平滑程度和资源回收节奏,但可不是设得越大越稳。有不少人把 max_wait_time 设成 300 秒,结果旧进程占着端口不放,新 worker 启动不了,整个服务反而卡住了。

  • reload_async => true 表示主进程不阻塞,异步触发 worker 退出;设为 false 时,主进程会等待每个 worker 自行退出,容易造成卡死。
  • max_wait_time 是 worker 收到退出信号后最多等待多久(秒),超时则强制 kill。建议设为略大于你最长请求耗时,比如 30 秒,但别超过 60 秒,否则旧进程赖着不走。
  • 如果用了协程 MySQL 或 Redis 客户端,务必在 onWorkerStop 中显式调用 close(),否则连接残留会导致新 worker 初始化失败。

如何确认重启真的“平滑”?

不能只看进程 PID 变了就万事大吉,得实际验证服务连续性。这里有几个实用方法:

  • curl -v http://127.0.0.1:9501/test 配合一个长 sleep 请求(比如接口里写 sleep(15)),在请求进行中发 kill -USR1,观察是否返回成功且没有 connection reset。
  • 检查 ps aux | grep php:旧 worker 进程状态应变为 Z(zombie)或消失,新 worker PID 全部更新,说明没有残留。
  • 记录 onWorkerStartonWorkerStop 日志,确认两者时间差合理。比如 stop 在 start 之前 2 秒内,说明没有“空窗期”,服务是连续的。
  • 避免在 onReceiveonRequest 中写全局变量或静态属性,因为 worker 重启后状态不继承,会导致数据错乱。

真正容易被忽略的是:Swoole 的 reload 只能更新 worker 进程的用户代码,Master 进程、Manager 进程、Task 进程的代码和配置都无法热更新。一旦涉及 server->set() 参数变更(如 worker_numtask_worker_num)、PHP 版本升级、扩展变动,就必须停机重启主进程——这时候就得靠蓝绿部署或滚动发布兜底了。

本文转载于:https://www.php.cn/faq/2823708.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注