$worker->count必须在worker::runall()前为每个udp worker单独设置,仅linux/macos生效;windows下始终单进程;udp多进程需权衡conntrack状态、心跳保活与rss内存限制,设错易丢包或oom。

$worker->count 必须在 Worker::runAll() 之前设置,且仅 Linux/macOS 生效;Windows 下无效,UDP 多进程配置不等于“开越多越稳”,错配会直接触发 OOM 或连接丢包。
UDP Worker 的 $worker->count 设置位置和生效条件
很多人把 $worker->count = 4 写在 onWorkerStart 回调里,或者写在 Worker::runAll() 之后——这两种写法完全不生效。Workerman 只在启动前读取该值,之后修改等于没改。
- 正确位置:Worker 实例创建后、
Worker::runAll()调用前 - 必须为每个 UDP Worker 实例单独设置,不能复用同一变量或全局覆盖
- Windows 系统下该设置被忽略,始终单进程运行(官方不支持多进程)
- UDP 场景下,
$worker->count > 1时底层自动切换为stream_socket,而非socket原生函数
UDP 多进程数量怎么选:不是看 CPU,而是看保活和连接态
UDP 无连接,但内核仍会为每个“通信对”(client IP:port ↔ server IP:port)维护一个短暂的连接状态(conntrack 表项)。多进程下这个状态分散在不同进程,容易导致客户端收不到回包。
- 用
stream_socket(即$worker->count > 1):首次通信后约 5 分钟内稳定,之后可能被内核丢弃;必须每 60 秒做一次双向心跳 - 用
socket(即$worker->count = 1):可长期维持通信对,适合 NAT/防火墙环境苛刻的场景 - 若业务需广播或群发(如 SIP 注册、视频流分发),建议
$worker->count = 1+ 连接池管理,避免跨进程状态不一致
实测 RSS 和系统限制比理论公式更重要
别信“单进程 5MB”这种空载数据。UDP Worker 加载 SIP 解析器、JSON 日志、自定义心跳逻辑后,实测 RSS 往往 40–70MB。设高了,ps aux --sort=-%mem | grep php 一眼就能看到爆内存进程。
- 估算上限公式只是起点:
最大安全 count ≈ (总内存 MB) ÷ 单进程 RSS(MB) × 0.8 - 必须压测:用真实 SIP 包或视频帧模拟并发,观察
%CPU和RSS是否线性增长 - Linux 上还要检查
net.netfilter.nf_conntrack_max和ulimit -n,UDP 高频短连接容易打满 conntrack 表
UDP 多进程最隐蔽的坑不在代码里,而在内核连接跟踪表和 NAT 超时策略——$worker->count 设得再准,心跳漏发一次,客户端就失联。











