向swoole主进程发送sigusr1信号是最可靠、最通用的平滑重启方式,它会逐个重启worker进程,确保每个进程处理完当前请求后再退出并加载新代码。

直接结论:向Swoole主进程发送SIGUSR1信号是最可靠、最通用的平滑重启方式,它会逐个重启worker进程,确保每个进程处理完当前请求后再退出并加载新代码。
为什么kill -USR1 <master_pid></master_pid>是首选操作
这是Swoole内核原生支持的信号机制,不依赖PHP扩展或第三方工具,兼容所有Swoole版本(>= 1.7.0)和部署环境(Docker、物理机、K8s等)。主进程收到SIGUSR1后,不会杀掉正在处理请求的worker,而是发信号让其“自停”——即等待当前onReceive、onRequest或协程任务结束,再退出。新worker随即启动,无缝接管流量。
常见误操作包括:
- 用
SIGTERM或SIGKILL:直接终止进程,必然丢请求 - 用
SIGHUP:部分旧版Swoole(如1.x)可能触发全量重启或无响应,行为不稳定 - 在未确认
master_pid时盲目执行:可能误杀其他进程
server->reload()方法的适用边界与陷阱
该方法本质是PHP层对SIGUSR1的封装,但仅在主进程上下文中有效(即必须在onWorkerStart、onManagerStart等回调里调用,且不能在子进程如task中调用)。它不适用于远程触发,也不支持带参数控制重启范围。
容易踩的坑:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 在
onReceive中调用$server->reload():会报错Operation not permitted,因为非主进程无权操作 - 期望它重载
onWorkerStart之前的全局代码:无效——该回调只在worker启动时执行一次,reload()只重新加载worker进程内的脚本(如require的业务文件),不重跑全局初始化逻辑 - 配合
opcache.enable_cli=1时未清理OPcache:新代码可能仍执行旧opcode,需额外调用opcache_invalidate()或禁用CLI OPcache
如何安全获取并验证master_pid
不能靠ps aux | grep swoole肉眼识别,易混淆manager或worker进程。正确做法是启动时显式写入PID文件:
$server->set([
'pid_file' => '/var/run/swoole_app.pid',
]);
然后通过以下方式触发和验证:
- 发送信号:
kill -USR1 $(cat /var/run/swoole_app.pid) - 检查worker是否更新:
ps --ppid $(cat /var/run/swoole_app.pid) -o pid,cmd,对比重启前后PID变化 - 观察日志:在
onWorkerStart里打印getmypid()和时间戳,确认新进程确实加载了最新代码 - 避免使用
max_wait_time设为0:设为30(秒)更稳妥,防止长连接或慢查询被强制中断
哪些更新不能靠平滑重启解决
SIGUSR1只影响worker和task进程,以下变更必须重启整个服务(即stop + start):
- Swoole扩展版本升级(如从v4.8.x升到v5.0.x)
- PHP版本切换(如PHP 8.1 → 8.2),涉及扩展ABI不兼容
- 修改
server->set()中的核心配置:如worker_num、max_conn、dispatch_mode等,这些由master进程解析,reload不生效 -
onWorkerStart中初始化的资源未设计为可重建:比如全局单例DB连接未在onWorkerStop中关闭,新worker复用旧连接句柄,可能引发状态混乱
真正需要关注的,不是“怎么发信号”,而是“代码是否准备好被反复加载”——比如把数据库连接、Redis客户端、配置读取全部移到onWorkerStart里,同时确保onWorkerStop能清理临时状态。否则,信号发得再准,也救不了内存里的脏数据。










