reactor_num是master进程内处理网络事件的线程数,worker_num是执行业务的独立子进程数,二者类型不同、无固定比例关系;需分别依据cpu核数/网络压力和业务阻塞程度配置,并满足reactor_num ≤ worker_num的硬约束。

reactor_num 是线程,worker_num 是进程,类型不同不能直接比
很多人一上来就想算 reactor_num 和 worker_num 的“比例”,比如 1:2 或 2:1 —— 这是典型误解。二者运行在不同层级:reactor_num 控制 Master 进程内负责网络事件监听和分发的线程数(每个线程持有一个 EventLoop),而 worker_num 是独立的 PHP 子进程,真正执行业务逻辑。
它们之间不是上下游配对关系,也没有固定绑定逻辑。Reactor 线程只管收包、解包、投递到 Worker,不参与业务处理;Worker 进程也不关心自己被哪个 Reactor 线程分发过请求。
所以别纠结“比例”,重点看各自是否匹配硬件与负载:
-
reactor_num主要看 CPU 核心数和网络吞吐压力:高并发短连接场景(如 WebSocket 心跳)可设为 CPU 核数 ×2;普通 HTTP API 用默认值(CPU 核数)通常就够 -
worker_num主要看业务阻塞程度:纯协程异步 I/O 场景下,4 核机器设 8~16 即可;若混有同步 MySQL 查询或文件操作,可能需要翻倍甚至更多,但必须同步监控内存(每个 Worker 常驻约 15–30MB) - 注意硬约束:
reactor_num≤worker_num,否则 Swoole 会自动截断 —— 这不是建议,是强制规则
reactor_num 超过 worker_num 会被静默修正
如果你写了这样的配置:
$server->set([
'reactor_num' => 32,
'worker_num' => 8,
]);
Swoole 不会报错,也不会拒绝启动,而是直接把 reactor_num 改成 8 并继续运行。你查 swoole_get_local_config() 或日志都看不到警告,只能通过 strace 或调试模式发现实际创建的线程数不对。
这种静默行为容易让人误判性能瓶颈:你以为是 Reactor 不够用导致连接堆积,其实根本没生效。排查时务必确认最终生效值:
- 启动后读取
/proc/<master_pid>/status</master_pid>中的Threads:行,对比预期 - 用
swoole_server::stats()查看reactor_threads字段(Swoole ≥ 4.8.0) - 压测时观察
reactor_idle_time是否持续接近 0 —— 若远低于 100%,说明 Reactor 其实有余量
worker_num 太大会让 reactor_num 的调优失去意义
当 worker_num 设置过大(比如 64+),而业务中存在较多同步阻塞操作(如 file_get_contents、curl_exec、未协程化的 PDO 查询),会导致大量 Worker 进入阻塞态。此时即使 Reactor 线程跑满,也没法提升吞吐 —— 因为请求来了,Worker 全在等 IO,根本没空处理。
这时候调高 reactor_num 不仅无效,反而增加调度开销。真实瓶颈其实在 Worker 层,解决路径是:
- 把阻塞操作替换成协程版(
co::readFile、Swoole\Coroutine\MySQL等) - 或拆出 Task 进程处理(需配
task_worker_num并注册onTask/onFinish) - 或者干脆降低
worker_num,配合更高并发的协程数(swoole_set_process_name+go)
换句话说:reactor_num 的上限价值,取决于 worker_num 能否及时消费它分发的请求。
超过 8 核的机器,reactor_num 默认被锁死为 8
Swoole ≥ 1.7.14 在检测到 CPU 核数 > 8 时,会把 reactor_num 默认设为 8,而不是按核数自动扩展。这个行为很反直觉,文档里提得隐晦,很多团队压测到瓶颈才意识到。
比如你有一台 32 核服务器,什么都没配,启动后实际只有 8 个 Reactor 线程 —— 即使网络连接数上万,也撑不死这 8 个线程,但整体吞吐卡在那儿上不去。
要绕过这个限制,必须显式设置:
$server->set([
'reactor_num' => 32, // 显式写死,不能依赖默认
]);
但要注意:设太高不一定更好。Linux 的 epoll 本身有单线程处理瓶颈,实测在 32 核机器上,reactor_num 设为 16~24 往往比 32 更稳,尤其当连接带宽不均或存在大量长连接时。
真正关键的不是“填满 CPU 核”,而是让每个 Reactor 线程的 idle_time 保持在 60%~85% 区间 —— 太低说明过载,太高说明浪费。











