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 实战:一个全球部署的架构图
下面是我画的一个全球部署架构图,展示了用户调度、边缘节点和跨区域桥接的关系。
27.6 避坑指南
最后,分享几个我在实际部署中踩过的坑:
- 我曾经以为 UDP 不需要健康检查。结果有一次某个 SFU 节点挂了,负载均衡器还在往它发 UDP 包,用户全部断连。后来我加了 UDP 心跳检测,每 5 秒检查一次节点存活状态。
- 我曾经忽略 TURN 服务器的容量规划。TURN 中继非常消耗带宽,一个 720p 的视频流大约需要 2Mbps。如果 1000 个用户同时走 TURN,带宽就是 2Gbps。一定要提前算好带宽,不然流量费会让你怀疑人生。
- 我曾经在跨区域桥接上踩过延迟坑。北京到纽约的专线延迟大约 150ms,如果桥接链路没有做优化,用户会明显感觉到卡顿。后来我加了 FEC(前向纠错)和 jitter buffer,才把体验拉回来。
我的建议:先小规模验证,再逐步扩展。不要一上来就搞 10 个节点。先部署 2-3 个节点,跑通流程,观察一个月,再慢慢加节点。大规模部署,稳比快重要。
好了,这一章的内容就到这里。负载均衡、集群架构、边缘计算、全球部署,每一个点单独拿出来都能讲很久。但核心思路就一句话:让用户离服务器更近,让媒体流走最优路径。记住这个原则,你的 WebRTC 服务就能扛住大规模流量。