$worker->count合理值为物理核心数的1.2~1.8倍;io密集型可升至2.0倍,启用reuseport后回调至1.2~1.5倍,需同步调高net.core.somaxconn并优化路由策略防单点瓶颈。

进程数设太多导致调度开销和锁竞争上升
Workerman 多进程不是线性叠加性能的。当 $worker->count 设得远超物理核心数(比如 32 核服务器设成 64),Linux 调度器会频繁切换进程上下文,cache line 失效变多,反而拖慢整体吞吐。更关键的是,多个 Worker 进程共享某些资源时会触发锁争抢——比如共用一个 Redis 连接池、写同一个日志文件、或访问未加锁的全局静态数组。
常见表现:
– top 看到 CPU %sy(系统态)占比异常高
– strace -c -p PID 显示大量 futex 调用
– 同一时刻多个 Worker 的 onMessage 回调里都在等同一个 file_put_contents(..., FILE_APPEND)
建议值:
– 物理核心数 × 1.2 ~ 1.8(例如 16 核 → 设 18~24)
– I/O 密集型业务(如频繁调外部 HTTP)可上浮至 ×2.0
– 若启用了 $worker->reusePort = true,可回调至 ×1.2~1.5,减少端口争抢干扰
reusePort 开了但 net.core.somaxconn 没调高
开了 $worker->reusePort = true 只是让多个 Worker 都能 bind() 同一端口,但真正决定“新连接能否被内核排队接收”的,是 net.core.somaxconn 参数。默认值通常只有 128,压测时大量 SYN 包进来,超出队列长度的直接被丢弃,现象就是客户端偶发 Connection refused 或超时,看起来像“多进程没生效”。
必须同步操作:
– 运行 sudo sysctl -w net.core.somaxconn=65535
– 写入 /etc/sysctl.conf 永久生效
– 在 Workerman listen 地址中显式加 backlog 参数:tcp://0.0.0.0:8080?backlog=65535
没做连接层负载均衡,流量全打到一个 BusinessWorker
如果你用的是 GatewayWorker 架构,压测发现只有一个 BusinessWorker 在干活,大概率是 Gateway 的路由策略没配对。默认 routerBind 是按 client_id 绑定固定 Worker,如果压测工具只建了一个 client(比如单个 WebSocket 连接反复发消息),所有请求就永远只进同一个进程。
解决方法:
– 改用 routerRand:在 Gateway.php 构造函数里设 $this->router = ['\GatewayWorker\Gateway', 'routerRand']
– 或改用 routerConsistentHash(需客户端 ID 有足够离散度)
– 压测时确保并发连接数 ≥ Worker 数,避免单连接复用掩盖问题
日志、配置、初始化逻辑塞在 onWorkerStart 里
onWorkerStart 是每个 Worker 进程启动时只执行一次,但很多人把日志初始化、大配置加载、同步 SDK 实例化全堆进去。结果是:进程数越多,重复加载越严重,内存暴涨 + 启动延迟拉长,压测刚开始就卡在初始化阶段。
典型错误:
– file_get_contents('huge_config.yaml') 在 onWorkerStart 里解析
– new AliyunOssClient(...)(同步 SDK)
– error_log('start') 或 file_put_contents('log.txt', ...) 写同步日志
正确做法:
– 配置提前解析好,存为常量或静态属性
– SDK 改用协程版(如 hyperf/oss)或延迟到 onMessage 中按需创建
– 日志走 SwooleCoroutineWriteFile 或异步队列
net.core.somaxconn 和 routerBind 这两个看似“配置完就没事”的项——它们不报错,但会让压测数据彻底失真。











