Master进程是单进程多线程结构,含1个MainReactor线程和若干Reactor线程(默认=CPU核数),负责网络IO与连接分发;Worker/Task进程均由Manager进程fork并管理,Master不直接创建它们。

Master 进程本身是单进程、多线程结构,它不 fork Worker,真正 fork 出 Worker 和 Task 进程的是 Manager 进程。 很多人误以为 Master 直接 spawn 所有子进程,结果在调试信号处理、进程崩溃恢复或 dispatch_mode 行为时踩坑——根源常在这里。
Master 进程到底包含哪些线程?
Master 进程启动后,内部会创建一组 Reactor 线程(默认数量 = CPU 核数),外加一个 MainReactor 线程(也叫主线程)。它们全在同一个进程地址空间内运行,由 C 层统一调度:
-
MainReactor负责监听 server socket,一旦accept()到新连接,就按负载(当前各 Reactor 的连接数)分发给某个 Reactor 线程 - 每个
Reactor线程独占一个 epoll/kqueue 实例,只管自己分配到的 TCP 连接:读数据、协议解析(如 HTTP 拆包)、拼包,再通过管道把完整请求投递给 Worker - Reactor 线程全程不执行 PHP 代码,也不调用用户回调;
onConnect/onReceive等回调一定发生在 Worker 进程里 - 如果你看到
strace -p $MASTER_PID显示大量epoll_wait调用,那基本就是 Reactor 线程在轮询
为什么说 “Master 不 fork Worker” 是关键认知?
这个点直接影响你对进程生命周期、信号转发和故障自愈的理解:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- Master 启动后,立刻 fork 出
Manager进程,之后所有 Worker/Task 进程均由Managerfork 并监控 - Worker 崩溃时,
Manager收到SIGCHLD,立即fork新 Worker 替补;Master 完全不参与这个过程 -
kill -USR1 $MASTER_PID触发平滑重启,实际是 Master 向 Manager 发送信号,再由 Manager 逐个 reload Worker - 若你在
onWorkerStart里做耗时初始化(比如连 Redis),而错误地把逻辑写在 Master 进程上下文(如全局变量赋值),它根本不会生效——因为 Worker 是全新 fork 的进程,不继承父进程的 PHP 堆内存
Reactor 线程和 Worker 进程的协作边界在哪?
数据从客户端到 PHP 回调的流转路径非常明确,跨线程/进程边界的隐式拷贝或阻塞极易引发问题:
- Reactor 线程收到 TCP 数据后,先缓存、拼包(例如合并多个
recv的小包),直到识别出完整 HTTP 请求头+body,才整包通过 Unix Pipe 写入 Worker - 这个 Pipe 是无名管道,容量有限(通常 64KB);如果 Worker 处理太慢、积压太多未读请求,Reactor 线程会阻塞在
write(),进而卡住整个连接池——表现为“连接突然变慢但 CPU 不高” -
worker_num配得太小,或 Worker 里混用了阻塞 IO(如file_get_contents),都会让 Pipe 快速堵死;此时需配合task_worker_num拆分耗时逻辑 - Reactor 线程无法被 PHP 代码直接访问,
swoole_process::signal或pcntl_signal在 Worker 里注册才有效;在 Master 进程里注册信号处理器是无效的
真正容易被忽略的是:Reactor 线程的“非阻塞”只针对网络 IO,它对 Pipe 写入仍是同步阻塞的。一旦 Worker 没及时消费,整个 Reactor 就会停摆——这不是配置能绕过的底层约束,必须靠业务逻辑解耦和合理设置 worker_num / task_worker_num 来规避。

















