将 WebSockets 扩展至 10 万连接:来自实时板球应用的经验教训
发布: (2026年4月25日 GMT+8 05:39)
5 分钟阅读
原文: Dev.to
Source: Dev.to
初始尝试及其局限
- 设置:一个运行
socket.io的 Node.js 进程;每个已连接的客户端都订阅所有实时比赛。 - 性能:
- 2 k 并发连接 – 正常工作。
- 15 k 连接 – 心跳开始丢失。
- 40 k 连接 – 事件循环延迟超过 3 秒;重连风暴让情况更糟。
要点:单个 Node 进程的上限大约在 20 k–40 k 套接字之间,具体取决于事件循环还在做什么。对所有客户端的广播在单进程中是 O(N) 的——一场热门比赛会拖慢整个循环。重连风暴是真实存在的:当你重启网关时,所有断开的客户端会在约 2 秒内重新连接,形成自发的 DDoS。
关键经验
- 无状态网关 – WebSocket 节点应当“傻瓜化”,只保持连接;不处理业务逻辑。
- Redis Pub/Sub 总线 – 使用以
match_id为键的 Redis 频道;每个网关订阅并在本地进行广播。 - 粘性会话 – 在 ALB 级别使用 cookie 实现粘性会话,使客户端始终连接到同一个网关,避免状态抖动。
架构重构
score provider → ingest worker → Redis PUB match:123
↘ N gateways SUB match:123 → WS push to clients
- 水平扩展:添加网关节点;Redis 将消息分发给所有网关。
- 单个 Redis 集群可以处理每秒数十万条 pub/sub 消息。
消息优化
- 仅发送增量消息。
{ "over": 14.3, "runs": 4, "batsman": "Kohli" }
- 与发送完整的 4 KB 快照相比,200 字节的增量可以把每个网关在 12 万连接下的出站带宽从约 480 MB/s 降至约 24 MB/s。这样大幅降低了所需实例规格。
处理慢速客户端
- 使用 2G 网络的移动客户端可能需要 8 秒才能 ACK 每条消息。
- 规则:如果客户端在 5 秒内未 ACK,则丢弃最旧的排队消息并发送
"resync"事件。客户端随后通过 REST 接口获取完整的记分卡并恢复 WebSocket。 - 这在用户体验上只会产生轻微卡顿,却能保证服务器稳定,防止 OOM 崩溃。
平滑重启与部署
- 在网关重启时,为每个客户端的重连延迟添加 0–5 秒的随机抖动。
- 服务器端优雅排空网关:ALB 停止分配新连接,已有连接完成当前消息后再退出进程。
- 滚动部署因此不再是突发事件。
健康监控
三个数字可以判断实时系统是否健康:
| 指标 | 期望阈值 |
|---|---|
| 事件循环延迟 (p99) | 提示:从一开始就使用 uWebSockets.js —— 它在原始 WebSocket 吞吐量上比 socket.io 高约 5 倍。提前构建负载削减机制:在高优先级事件(如 “wicket”)之前先丢弃低优先级事件(如 “commentary”)。 |
结论
无论是直播体育、协同编辑、交易平台还是实时仪表盘——WebSocket 的扩展都是一门充满棱角的技术。如果你在这个领域构建系统,Xenotix Labs 已经交付了能够承受印度赛日流量的实时技术栈。欢迎通过 . 联系我们。