workerman的count应据io或cpu密集型业务设定:io密集型建议cpu核数×3–5,cpu密集型设为cpu核数或+1;需结合内存限制估算上限,并通过压测与监控动态调优。

Workerman的count设多少?先看你的业务是“等IO”还是“算得快”
Workerman的count不是越大越好,也不是照搬CPU核数就稳。它本质是“同时能干活的工人数量”,而工人干的活分两类:一类总在等数据库、Redis、HTTP下游响应(IO密集型),一类几乎不等、纯计算或非阻塞IO(CPU密集型)。
常见错误现象:count设成64,结果内存爆满、进程频繁OOM;或者只设2,4核机器常年CPU不到30%,并发上不去。
- 如果你用
mysqli、pdo_mysql、redis->get()这类**阻塞式调用**——属于IO密集型,count建议设为CPU核数 × 3起,可到5倍(比如8核就试24–40) - 如果你用
Workerman\Connection\AsyncTcpConnection、Swoole\Coroutine\MySQL或纯JSON解析/算法处理——属于CPU密集型,count设为CPU核数或CPU核数 + 1更合理 - 不确定类型?从
CPU核数 × 2起步,压测时观察top里PHP进程的%CPU和VIRT内存占用,再微调
别只看CPU核数,内存才是硬门槛
每个Worker进程启动后常驻内存约30–60MB(取决于加载的类库、配置、是否开调试),不是“空进程=0内存”。设高了,没等压测就Cannot allocate memory。
实操建议:用这个公式快速估算上限——最大安全count ≈ 总内存(GB) × 1024 ÷ 单进程预估内存(MB)
- 举例:16GB内存服务器,预估单进程占48MB →
16 × 1024 ÷ 48 ≈ 341,但这是理论极限,实际应保留20%余量,设≤270 - 线上务必用
ps aux --sort=-%mem | grep php实测几个Worker进程的真实RSS值,替换“预估内存” - 如果用了
opcache.enable=1且opcache.memory_consumption较大,单进程内存会上浮,要计入
reusePort开启后,count还能再拉高吗?
开了reusePort(即$worker->reusePort = true;),内核会把新连接哈希分发到不同Worker,避免“惊群”浪费CPU。但这不等于可以无脑加count——它解决的是“唤醒效率”,不是“内存/IO瓶颈”。
使用场景:单机扛10万+连接、长连接服务(如IM网关)、Nginx反向代理直连Workerman时特别有效。
- 开启后,
count仍需遵守内存约束,但可比不开时多10–20%(例如原设24,开reusePort后试28) - 必须确认Linux内核≥3.9(
uname -r),否则reusePort无效,日志里也不会报错,只会静默退化为普通模式 - PHP需≥7.0,且
stream_socket_server()底层支持SO_REUSEPORT,低版本PHP可能忽略该选项
线上动态调优:别靠猜,用数据说话
上线后改count不是改完重启就完事。真实负载下,它的效果藏在指标里。
关键监控项:
-
Worker::getTotalConnections()持续接近count × 65535?说明连接数逼近单进程上限,该横向扩容或检查连接泄漏 - 用
strace -p $(pgrep -f "Worker::runAll") -e trace=accept,send,recv看系统调用频率,若accept大量失败或send阻塞,可能是count不足或下游拖慢 - 观察
netstat -ant | awk '$6 ~ /ESTABLISHED/ {print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -10,客户端IP分布是否严重倾斜?如果是,reusePort可能未生效
最易被忽略的一点:Workerman自身不管理数据库连接池。哪怕count=1,你代码里每次请求都new PDO(),照样崩。进程数只是第一层水位线,后面全靠业务代码是否真正异步、复用资源。









