27、大规模部署:负载均衡、集群架构、边缘计算、全球部署方案

说实话,WebRTC 的 demo 跑起来很容易。两台电脑在同一局域网,信令一交换,视频就出来了。但一旦你要服务几千、几万甚至几十万用户,事情就完全不一样了。我最早做的一个项目,上线第一天只有 200 人同时在线,服务器就扛不住了——CPU 飙到 90%,用户画面卡成 PPT。嗯,从那以后,我再也不敢小看「部署」这两个字。

这一章,我们就来聊聊大规模部署的那些事。说白了,就是怎么让 WebRTC 服务扛住流量,还能在全球范围内低延迟跑起来。

27.1 负载均衡:别让一台服务器累死

WebRTC 的负载均衡,和普通 HTTP 负载均衡不太一样。为什么?因为 WebRTC 是长连接,而且媒体流是 UDP 的。你想想看,HTTP 请求来了就回,回完就断,但 WebRTC 的媒体流可能持续几十分钟甚至几小时。

我个人习惯把负载均衡分成两层:

  • 信令层负载均衡:处理 HTTP/WebSocket 请求,这个和普通负载均衡一样,用 Nginx 或 HAProxy 就行。
  • 媒体层负载均衡:处理 UDP 媒体流,这个比较特殊,需要专门设计。

核心原则:信令层可以随便分发,但媒体层必须保证同一个通话的所有参与者落在同一组服务器上。

我在项目中遇到过一个问题:用户 A 和用户 B 建立通话,结果 A 被分到了服务器 1,B 被分到了服务器 2。两个服务器之间没有媒体通道,结果就是——谁也看不见谁。这就是典型的「媒体流亲和性」问题。

27.2 集群架构:SFU 的横向扩展

WebRTC 的媒体服务器,主流方案是 SFU(Selective Forwarding Unit)。SFU 负责转发媒体流,不混流,所以 CPU 消耗相对较低。但即便如此,单台 SFU 也有瓶颈。

我建议的集群架构是这样的:

+------------------+
|   负载均衡器      |  <-- 信令层 (Nginx/HAProxy)
+--------+---------+
         |
+--------+---------+
|   信令服务器集群   |  <-- 管理房间、用户状态
+--------+---------+
         |
+--------+---------+
|   SFU 媒体集群    |  <-- 转发媒体流
+--+---+---+---+---+
   |   |   |   |
  SFU1 SFU2 SFU3 SFU4

这里有个关键设计:房间亲和性。同一个房间的所有用户,必须连接到同一个 SFU 节点。否则,媒体流需要在 SFU 之间转发,延迟和带宽都会翻倍。

实现技巧:在信令层做哈希路由,用房间 ID 做 key,把同一个房间的请求固定路由到同一个 SFU 节点。我习惯用一致性哈希,这样节点增减时影响最小。

27.3 边缘计算:把服务器推到用户家门口

全球部署最大的挑战是什么?延迟。从北京到纽约,光速也要 60ms 以上,加上网络抖动,实际延迟可能到 200ms。对于实时通信来说,200ms 已经能感觉到明显卡顿了。

边缘计算的核心思路很简单:在离用户最近的地方部署 SFU 节点

举个例子:

  • 中国用户 → 连接上海/北京的边缘节点
  • 美国用户 → 连接纽约/洛杉矶的边缘节点
  • 欧洲用户 → 连接法兰克福/伦敦的边缘节点

我曾经帮一个跨国教育平台做过优化。他们原本所有流量都走新加坡节点,结果欧洲用户延迟 300ms+。后来我们在法兰克福和伦敦各部署了一个边缘节点,欧洲用户延迟降到 30ms 以内。效果立竿见影。

27.4 全球部署方案:选型与架构

全球部署,说白了就是解决两个问题:用户怎么找到最近的节点,以及跨区域节点之间怎么通信

27.4.1 用户调度:DNS 解析 + Anycast

我常用的方案有两种:

方案 原理 优点 缺点
DNS 解析 根据用户 IP 返回最近的节点 IP 实现简单,成本低 DNS 缓存可能导致调度不准确
Anycast 多个节点共享同一个 IP,路由协议自动选择最近节点 调度精准,故障切换快 需要 BGP 支持,成本较高

我个人习惯:小规模用 DNS 解析,大规模用 Anycast。如果你有 10 个以内的节点,DNS 解析完全够用。超过 10 个节点,Anycast 的运维成本反而更低。

27.4.2 跨区域通信:TURN 中继 + 媒体桥接

跨区域通信是个麻烦事。两个用户在不同区域,如果直接 P2P,延迟可能很高。如果都连到同一个 SFU,又失去了边缘计算的优势。

我建议的方案是:区域内部走边缘 SFU,区域之间走媒体桥接

用户A(北京) → 北京SFU → 媒体桥接 → 纽约SFU → 用户B(纽约)

媒体桥接的作用是:把北京 SFU 的媒体流转发给纽约 SFU。这样,用户 A 和用户 B 都只连接最近的 SFU,延迟最低。跨区域的延迟只发生在桥接链路上,而且可以通过专线优化。

注意:跨区域桥接会引入额外的带宽成本。如果两个区域之间用户通话量很大,建议在桥接链路上做带宽限制或 QoS 优先级。

27.5 实战:一个全球部署的架构图

下面是我画的一个全球部署架构图,展示了用户调度、边缘节点和跨区域桥接的关系。

全球 WebRTC 部署架构 用户A (北京) 用户B (纽约) DNS/Anycast 调度 北京边缘节点 SFU + TURN 纽约边缘节点 SFU + TURN 媒体桥接 (专线) 跨区域媒体转发 中心信令集群 房间管理/用户状态 用户 边缘节点 媒体桥接 信令集群

27.6 避坑指南

最后,分享几个我在实际部署中踩过的坑:

  • 我曾经以为 UDP 不需要健康检查。结果有一次某个 SFU 节点挂了,负载均衡器还在往它发 UDP 包,用户全部断连。后来我加了 UDP 心跳检测,每 5 秒检查一次节点存活状态。
  • 我曾经忽略 TURN 服务器的容量规划。TURN 中继非常消耗带宽,一个 720p 的视频流大约需要 2Mbps。如果 1000 个用户同时走 TURN,带宽就是 2Gbps。一定要提前算好带宽,不然流量费会让你怀疑人生。
  • 我曾经在跨区域桥接上踩过延迟坑。北京到纽约的专线延迟大约 150ms,如果桥接链路没有做优化,用户会明显感觉到卡顿。后来我加了 FEC(前向纠错)和 jitter buffer,才把体验拉回来。

我的建议:先小规模验证,再逐步扩展。不要一上来就搞 10 个节点。先部署 2-3 个节点,跑通流程,观察一个月,再慢慢加节点。大规模部署,稳比快重要。

好了,这一章的内容就到这里。负载均衡、集群架构、边缘计算、全球部署,每一个点单独拿出来都能讲很久。但核心思路就一句话:让用户离服务器更近,让媒体流走最优路径。记住这个原则,你的 WebRTC 服务就能扛住大规模流量。

公众号:蓝海资料掘金营,微信 deep3321