worker_num无固定最优值,需依CPU核数、业务类型(IO/CPU密集型)及内存水位动态调优:IO密集型可设为CPU核数×2,CPU密集型宜设为核数或+1~2,协程启用后应优先调max_coroutine而非盲目提高worker_num。

没有“最合适”的固定值,只有贴合你当前 CPU 核数、业务类型和内存水位的合理值。盲目套用“CPU 核数 × 2”或直接设成 32/64,线上大概率会 OOM 或调度抖动。
worker_num 设太高会直接吃光内存
每个 worker_num 进程独占内存:加载的类、扩展、协程栈、连接池实例都会被复制一份。大项目里单个 worker 常驻内存约 20–40MB:
-
worker_num = 32→ 约占用 1–1.3GB 内存(未算 PHP 自身开销) -
worker_num = 64→ 很容易突破 2.5GB,2GB 内存机器直接触发 OOM killer - 用
Table或Channel共享结构时,总内存不是线性叠加,但 worker 越多,争抢和碎片越明显
IO 密集型 vs CPU 密集型,配置逻辑完全不同
关键看你的请求卡在哪:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- IO 密集型(如 API 聚合、LLM 网关、查 Redis/MySQL):
worker_num可设为swoole_cpu_num() * 2,比如 8 核 →16;再多意义不大,瓶颈在网卡、DB 连接池或远程服务延迟 - CPU 密集型(如图像缩放、同步计算、JSON 深度解析):
worker_num宜保守设为swoole_cpu_num()或 +1~2,比如 4 核 →4或5;再高只会加剧上下文切换,top里看到%si(软中断)飙升就是信号 - Laravel-Swoole 类项目要额外注意:每个 worker 默认建满 MySQL 连接池(如 10 个),
worker_num=8就可能打爆 MySQL 的max_connections=151
开了 enable_coroutine 后,worker_num 就不该再拉高
这是最常踩的语义陷阱:协程模式下,worker_num 控制的是进程数,不是并发能力上限;真正跑并发的是 max_coroutine。
-
enable_coroutine = true时,worker_num推荐设为1~4(依 CPU 核数),重点调max_coroutine(如3000~65536) - 若仍设
worker_num = 32+enable_coroutine = true,会出现大量空闲 worker 争抢事件循环,strace可见高频epoll_wait返回 0,QPS 不升反降 - 验证是否生效:改完执行
ps aux | grep php,确认实际 worker 进程数;systemd 或 supervisor 若拦截 reload,配置就白改
真实瓶颈往往不在 worker_num,而在阻塞调用
压测发现 QPS 上不去、延迟毛刺多?先别急着调 worker_num:
- 检查有没有在协程里用
sleep()、usleep()、file_get_contents()(未用协程版)、curl_exec()(未用Swoole\Coroutine\Http\Client) - Redis 同步调用、未设超时的 cURL、阻塞式日志写入(如
fopen(..., 'a')写磁盘文件),会让整个 worker 卡住,再多进程也无济于事 - 用
swoole_server->stats()看request_count和worker_request_count是否均衡;若某些 worker 长期request_count == 0,说明被卡死或没流量分到
最终得靠压测数据说话:从 swoole_cpu_num() 开始,每次 ±2,观察 QPS、95% RT、内存增长和 ps 进程状态。超过 32 还没明显收益,基本可以断定是代码或下游问题,不是 worker_num 不够。

















