平滑重启需主进程逐个通知worker处理完当前请求再退出并启动新worker加载新代码;关键前提是业务代码必须在onWorkerStart中加载,否则kill -USR1不生效,因全局作用域已加载的文件不会被重载。
平滑重启不是“发个信号就完事”,而是主进程逐个通知 worker 处理完当前请求再退出,新 worker 加载新代码接替——前提是你的业务代码必须在 onWorkerStart 之后加载,否则改了也白改。
常见错误现象:改完代码发 kill -USR1 $pid,日志没刷新、onWorkerStart 没重跑、旧逻辑还在执行。
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 => true 表示主进程不阻塞,异步触发 worker 退出;设为 false 时,主进程会等待每个 worker 自行退出,容易卡住max_wait_time 是 worker 收到退出信号后最多等待多久(秒),超时则强制 kill;建议设为略大于你最长请求耗时(如 30 秒),但不要设成 300+,否则旧进程占着端口不放onWorkerStop 中显式 close(),否则连接可能残留导致新 worker 初始化失败不能只看进程 PID 变了,得验证服务连续性。
curl -v http://127.0.0.1:9501/test 配合长 sleep 请求(比如返回 sleep(15) 的接口),在请求进行中发 kill -USR1,观察是否返回成功且无 connection resetps 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 版本升级、扩展变动,就必须停机重启主进程——这时候就得靠蓝绿部署或滚动发布兜底。