workerman性能优化需分四步:一设合理worker数(io型×3、cpu型≈核数),二启reuseport防惊群,三调somaxconn与nofile防丢连,四禁同步日志改redis+消费者落盘,并复用mongodb连接池。

合理设置Worker进程数
Workerman的count值不能直接套用CPU核心数,必须按业务类型区分设定。
第一步:执行nproc命令获取服务器实际CPU核数,例如返回8,则基础值为8。
第二步:判断业务类型——若大量调用MySQL、Redis或HTTP API,属于IO密集型,count设为8 × 3 = 24起步;若主要做JSON编解码、加密计算等纯逻辑运算,属于CPU密集型,count设为8 或 9更稳。
第三步:在Worker实例初始化后立即赋值,代码写成$worker->count = 24;,不能放在onWorkerStart里动态改,否则无效。
注意:内存才是硬瓶颈,每个Worker进程常驻内存约30–60MB,设高了容易触发OOM。实测单进程RSS为48MB、总内存16GB时,安全上限≈(16 × 1024) × 0.8 ÷ 48 ≈ 273,但线上建议先设≤200,观察负载再调。
启用端口复用(reusePort)
启用reusePort能缓解“惊群”现象,让内核在新连接到达时哈希分发到不同Worker,避免所有进程被唤醒却只有一个能accept。
方法一:直接在Worker初始化后设置属性:$worker->reusePort = true;
方法二:若使用GatewayWorker架构,在start_gateway.php中对$gateway对象同样设置$gateway->reusePort = true;
【必须同步验证ss -lnt输出中目标端口的Send-Q是否达到预期值】,否则说明没生效。
调大内核全连接队列(somaxconn)
Workerman静默丢连接的根源是内核全连接队列满后丢弃ACK包且不发RST,netstat看不出异常,但ss -lnt的Recv-Q会持续逼近Send-Q。
执行sudo sysctl -w net.core.somaxconn=65535临时生效;永久生效需写入/etc/sysctl.conf并运行sysctl -p。
仅改somaxconn不够,必须同步调整/etc/security/limits.conf中的nofile为1048576,并启用net.ipv4.tcp_tw_reuse = 1。
验证是否生效:启动Workerman后执行ss -lnt | grep :端口号,Send-Q列必须显示65535。
禁用同步文件日志
不能在Worker进程里用file_put_contents同步写日志,QPS超200就开始排队,超500易触发max_execution_time超时或Too many open files错误——根源是flock阻塞卡死事件循环。
必须改用Redis中转+独立消费者落盘方案。
在配置中注册Monolog实例,handler使用Monolog\Handler\RedisHandler,构造时必须传['timeout' => 0.1, 'read_write_timeout' => 0.1],否则Redis偶发延迟会卡住主线程。
消费者启动命令用php webman queue:work --tries=3 --delay=100,且代码里必须加try-catch兜底写入fallback.log,Redis故障时日志不能静默消失。
优化MongoDB连接复用
Workerman常驻进程下各Worker独立创建连接池,会导致maxPoolSize被乘以Worker数而打满MongoDB连接上限,引发卡死或连接耗尽。
方法一:在onWorkerStart中单例复用MongoDB\Driver\Manager,连接字符串显式指定minPoolSize=2&maxPoolSize=20&maxIdleTimeMS=60000。
方法二:全局静态变量存储Manager实例,禁止在onMessage回调里反复new,否则高并发下开销爆炸。
【必须禁用MongoDB\Client类,它内部为每次操作新建Session】,只用MongoDB\Driver\Manager + BulkWrite组合。











