最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
重点解析 Swoole 如何实现平滑重启面试题
时间:2026-07-27 08:04:53 编辑:袖梨 来源:一聚教程网
平滑重启需主进程逐个通知worker处理完当前请求再退出并启动新worker加载新代码;关键前提是业务代码必须在onWorkerStart中加载,否则kill -USR1不生效,因全局作用域已加载的文件不会被重载。
平滑重启不是“发个信号就完事”,而是主进程逐个通知 worker 处理完当前请求再退出,新 worker 加载新代码接替——前提是你的业务代码必须在 onWorkerStart 之后加载,否则改了也白改。
为什么 kill -USR1 有时不生效?
常见错误现象:改完代码发 kill -USR1 $pid,日志没刷新、onWorkerStart 没重跑、旧逻辑还在执行。
- 根本原因:被修改的 PHP 文件在 server 启动前(全局作用域)就已
require或include,Swoole reload 不会重新加载这些文件 - 正确做法:所有业务类、配置、数据库连接等,必须延迟到
onWorkerStart回调里加载或初始化 - 验证方式:在
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 怎么配才不丢请求?
这两个参数直接影响平滑程度和资源回收节奏,不是设得越大越稳。
-
reload_async => true表示主进程不阻塞,异步触发 worker 退出;设为false时,主进程会等待每个 worker 自行退出,容易卡住 -
max_wait_time是 worker 收到退出信号后最多等待多久(秒),超时则强制 kill;建议设为略大于你最长请求耗时(如 30 秒),但不要设成 300+,否则旧进程占着端口不放 - 如果用了协程 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 应全部更新 - 记录
onWorkerStart和onWorkerStop日志,确认两者时间差合理(比如 stop 在 start 之前 2 秒内),说明没有“空窗期” - 避免在
onReceive或onRequest中写全局变量或静态属性,worker 重启后状态不继承,会导致数据错乱
真正容易被忽略的是:Swoole 的 reload 只能更新 worker 进程的用户代码,Master 进程、Manager 进程、Task 进程的代码和配置无法热更新。一旦涉及 server->set() 参数变更(如 worker_num、task_worker_num)、PHP 版本升级、扩展变动,就必须停机重启主进程——这时候就得靠蓝绿部署或滚动发布兜底。