将 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。

关键经验

  1. 无状态网关 – WebSocket 节点应当“傻瓜化”,只保持连接;不处理业务逻辑。
  2. Redis Pub/Sub 总线 – 使用以 match_id 为键的 Redis 频道;每个网关订阅并在本地进行广播。
  3. 粘性会话 – 在 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 已经交付了能够承受印度赛日流量的实时技术栈。欢迎通过 . 联系我们。

0 浏览
Back to Blog

相关文章

阅读更多 »

数据库瓶颈

“它很快……直到用户出现。” 那是我在调试他系统时对朋友说的。问题是每个请求都依赖于 database。每…