Workerman的onConnect是雪崩起点,因其同步执行且无内置限速,高并发连接会并行触发该回调,若含IO或CPU密集操作(如DB查询、JWT解析),将迅速耗尽worker资源导致进程卡死或崩溃。

Workerman服务端因客户端频繁重连而雪崩,本质是连接风暴击穿了进程承载能力——不是单个连接的问题,而是 onConnect 回调里未做节流、未校验、未隔离,导致 CPU/内存/文件描述符在短时间内被耗尽。必须从连接入口层直接拦截,不能等它进到业务逻辑再处理。
为什么 Workerman 的 onConnect 会成为雪崩起点?
Workerman 的 onConnect 是同步执行的,且默认无任何限速或排队机制。一旦大量客户端(比如网络抖动后集体重连、恶意扫描、前端未加退避的自动重连)在几秒内发起连接,所有连接请求会并行触发 onConnect 回调。如果里面做了数据库查询、Redis 认证、JWT 解析等 IO 或 CPU 密集操作,worker 进程会迅速卡死或崩溃,主进程反复拉起新进程,最终整个服务不可用。
- 常见错误现象:
Too many open files、Worker process exit异常退出、cpu 100% 但无有效请求处理日志 - 关键误判点:很多人以为是 WebSocket 握手慢或
onMessage处理不及时,其实问题早在onConnect就已发生 - 性能影响:一个未加防护的
onConnect在 1000+ 并发连接下,可能让单 worker 吞吐下降 70% 以上
如何在 onConnect 阶段做轻量级准入控制?
准入控制必须满足两个条件:快(微秒级)、无依赖(不查 DB/Redis)。推荐用内存计数 + 时间窗口 + 客户端标识组合实现,避免引入外部瓶颈。
- 用
$_SERVER['REMOTE_ADDR']+$_SERVER['HTTP_USER_AGENT']做粗粒度指纹(防脚本批量重连) - 用
pcntl_fork()不可行,改用apcu_inc()或memory_get_usage()辅助判断内存压力 - 最简可行方案:每秒每个 IP 允许最多 5 次连接,超限直接
$connection->close(),不进业务逻辑 - 示例代码片段:
// 在 onConnect 中 $clientIp = $_SERVER['REMOTE_ADDR']; $key = 'connect_limit_' . $clientIp; $count = apcu_fetch($key, $success) ?: 0; if ($success && $count >= 5) { $connection->close(); return; } apcu_store($key, $count + 1, 1); // 1秒过期
为什么不能只靠 nginx 层限连?
nginx 的 limit_conn 只能按 IP 或 key 限并发连接数,对短连接重连无效;而 Workerman 的 WebSocket 是长连接,客户端断开后立即重连,IP 连接数始终 ≤1,limit_conn 完全失效。更麻烦的是,很多部署走的是 SLB 或 k8s Service,真实客户端 IP 已被抹掉,nginx 看到的全是后端节点 IP。
- 典型失效场景:k8s Ingress → nginx → Workerman,nginx 日志里全是
10.244.x.x,限连失去意义 - 真正有效的限连必须落在 Workerman 进程内,且基于四层信息(如 TCP timestamp、TLS SNI)或七层信息(如
Sec-WebSocket-Key前缀)做指纹 - 若必须用 nginx,至少配
limit_req zone=connburst burst=10 nodelay,但仅作辅助,不能替代进程内控制
连接认证阶段如何避免阻塞 worker?
把 JWT 校验、token 查询这类操作放在 onConnect 里同步执行,等于把 IO 压力直接甩给 worker。正确做法是:先放行连接,再异步认证,失败则静默关闭。
- 用
$connection->send()发送欢迎消息后,立刻启动Timer::add()延迟 3 秒等待认证数据 - 认证数据通过
onMessage上行发送,服务端比对$connection->id关联状态 - 若超时未收到认证消息,调用
$connection->close(),不占用 worker 主循环 - 切忌在
onConnect里调用file_get_contents、curl_exec、PDO::query等同步阻塞操作
真正难的不是写限流逻辑,而是区分哪些连接该被拦在门外、哪些该被“挂起观察”——比如同一 IP 的第 6 次连接,到底是恶意扫描,还是用户切了 WiFi 后重连?这需要结合客户端上报的设备 ID、时间戳、重连间隔等上下文做动态判断,纯静态阈值只是保底手段。

















