拓扑选型Mesh-SFU-MCU
WebRTC 多人通信只有三种基本拓扑:Mesh、SFU、MCU。选错拓扑,后面的所有优化都无解。本文给出带宽公式、成本估算、决策树和切换信号,目标是让读者在 10 分钟内对项目做出正确判断。
决策原则:1v1 用 P2P;3 人以下可以 Mesh;从第 4 个人开始就要评估 SFU;MCU 仅在弱端或合规要求合流时使用。
1. 三种拓扑的本质区别
| 维度 | Mesh | SFU(Selective Forwarding Unit) | MCU(Multipoint Conferencing Unit) |
|---|---|---|---|
| 谁路由媒体 | 客户端互连 | 服务器只转发不解码 | 服务器解码 + 合流 + 重编码 |
| 上行连接数 | N-1 | 1 | 1 |
| 下行连接数 | N-1 | N-1 | 1 |
| 服务器算力 | 0 | 低(不解码) | 极高(每路要解码 + 合成 + 编码) |
| 客户端算力 | (N-1) 路解码 | (N-1) 路解码 | 1 路解码 |
| 端到端加密 | 天然 E2EE | 默认只到 SFU;可叠加 Insertable Streams 实现 E2EE | 服务器必须解密,无法 E2EE |
| 自由度 | 各端自己渲染 | 各端自己渲染 | 服务端定布局 |
记忆点:Mesh = 网格状,SFU = 中转站只转包,MCU = 把所有人捏成一路画面。
2. 带宽公式(请把它贴到工程师工位上)
设单路视频码率为 B(kbps),房间人数为 N:
| 拓扑 | 单端上行 | 单端下行 | 服务端上行 | 服务端下行 |
|---|---|---|---|---|
| Mesh | (N-1) × B | (N-1) × B | 0 | 0 |
| SFU(仅订阅自己以外的人) | B(或 simulcast 多层) | (N-1) × B | (N × (N-1)) × B | (N × (N-1)) × B |
| MCU(合流后单路下发) | B | 1 × B(合成路) | N × B | N × B(合流后下行的总和受订阅者数影响) |
举例:720p @ 1.5Mbps,N=10 人房间:
- Mesh:每个客户端上行 9 × 1.5 = 13.5 Mbps,下行 13.5 Mbps —— 普通家用上行扛不住
- SFU:每个客户端上行 1.5 Mbps,下行 9 × 1.5 = 13.5 Mbps —— 端依然要解 9 路,可结合 Simulcast 让下行降到 4-5 Mbps
- MCU:每个客户端上行 1.5 Mbps,下行 1.5 Mbps —— 但服务器要解 10 路 + 合 1 路 + 编 10 路,单路 MCU 比 SFU 贵 5-10 倍 CPU
3. 决策树
4. 什么时候用 Mesh
4.1 适用
- 1v1 场景(语音、视频通话、客服、面试)
- 内部调试 demo / hackathon 原型
- 端到端加密硬性要求且 N ≤ 3
4.2 不适用
- N ≥ 4。原因:上行带宽线性增长。家庭宽带上行通常 30-100 Mbps,4 人 720p 已经接近上限
- 移动端为主的房间。运营商上行更紧、被基站限速
- 任何需要服务端录制 / 转推 / AI 处理的场景
4.3 失败时的样子
- 加入第 4 个人后视频开始卡顿,CPU 飙到 90%+
- 弱网用户进来后所有人都被 TWCC 压低码率(每个发送方独立估带宽)
- 移动端发热严重,几分钟后系统主动降帧
4.4 工程实现要点
// Mesh 中每多一个人就多一条 PeerConnection
class MeshRoom {
pcs = new Map(); // userId -> RTCPeerConnection
localStream = null;
async addPeer(userId, signaling) {
const pc = new RTCPeerConnection(this.config);
this.localStream.getTracks().forEach((t) => pc.addTrack(t, this.localStream));
pc.ontrack = (e) => this.onRemoteTrack(userId, e);
pc.onicecandidate = (e) => e.candidate && signaling.send(userId, e.candidate);
this.pcs.set(userId, pc);
// 注意:N-1 条 PC 全部要做 Offer/Answer,信令复杂度 O(N²)
}
}
Mesh 的真正麻烦不是带宽,是信令复杂度 O(N²):每一对人都要交换 Offer/Answer/ICE。N=10 已经是 45 对。
5. 什么时候用 SFU
5.1 适用
- 5 ≤ N ≤ 50 的会议、教学、互动直播连麦
- 需要服务端录制、转推、AI 处理
- 发布订阅模型清晰(哪些 track 要订给谁)
5.2 不适用
- 万人观看类直播。SFU 下行成本随订阅者线性增长,不如 CDN 扇出
- 服务端必须看到明文媒体流(MCU 的活)
- 端 CPU 极弱且不能容忍 Simulcast 多层订阅切换
5.3 失败时的样子
- 没开 Simulcast → 弱网用户拉到 1080p 反复卡顿,整房间被拖慢
- 没开 TWCC / REMB → SFU 不知道下行端拥塞,瞎发
- 单实例扛全量 → 跨地区用户 RTT 高,挂掉就全断
5.4 SFU 必备能力清单
| 能力 | 没有的后果 |
|---|---|
| Simulcast / SVC 转发 | 弱网拉低强网 |
| TWCC(transport-cc)反馈 | 码率自适应失效 |
| RTX 重传转发 | 丢包恢复差 |
| PLI/FIR 关键帧请求 | 切层 / 新订阅黑屏久 |
| ICE Restart 支持 | 切网络断连不可恢复 |
| Insertable Streams 透传 | 无法叠加 E2EE |
6. 什么时候用 MCU
6.1 适用
- 端硬件极弱(IoT 屏、老旧 STB)只能解 1 路
- 合规要求统一画面(合规录像、监管转推)
- 与 RTMP / SIP 等单流协议互通时的最后一跳合流
6.2 不适用
- 现代浏览器 / 手机为主。它们解多路是常态,没必要花服务端 GPU
- 需要灵活布局(每端自己定大小)
- 成本敏感的高并发会议
6.3 失败时的样子
- 服务端 GPU 排队,合流延迟升到 500ms+
- 改个布局要改服务端配置,迭代慢
- 一个房间一个 MCU 实例,10 万房间要 10 万 GPU 切片
6.4 实现形态
MCU 通常不直接落地,而是 SFU 旁路一个合流服务:
合流服务可用 FFmpeg filter_complex 做画中画或宫格:
ffmpeg \
-i "rtp://sfu:5004" -i "rtp://sfu:5006" -i "rtp://sfu:5008" \
-filter_complex "
[0:v]scale=640:360[a];
[1:v]scale=640:360[b];
[2:v]scale=640:360[c];
[a][b]hstack=2[top];
[top][c]vstack=2[out];
[0:a][1:a][2:a]amix=inputs=3[aout]
" \
-map "[out]" -map "[aout]" \
-c:v libx264 -preset veryfast -tune zerolatency -b:v 2500k \
-c:a aac -b:a 128k -f flv rtmp://cdn/live/room1
7. 成本估算(数量级)
按 720p / 1.5 Mbps 单路、AWS 公网带宽 0.09 USD/GB 估算每分钟成本:
| 拓扑 | 服务器 CPU | 服务器带宽 | 单房间(10人/小时) 估算 |
|---|---|---|---|
| Mesh | 0 | 0 | 服务费仅信令,几乎可忽略 |
| SFU | 1-2 vCPU 单实例千路 | 主要成本 | ~1.6 USD/小时(10 人房间下行 13.5 Mbps × 10) |
| MCU | 1 vCPU/路 解码+编码 | 单路下行 | ~3-5 USD/小时(CPU 主导) |
经验:SFU 把成本压在带宽上,MCU 把成本压在 CPU 上。带宽便宜的云厂商更适合 SFU;自建 IDC 有 GPU 富余的场景 MCU 才划算。
8. 拓扑切换信号:什么时候该升级架构
| 信号 | 当前拓扑 | 应迁移至 |
|---|---|---|
| 单端上行 > 80% 用户家宽上行 | Mesh | SFU |
qualityLimitationReason: bandwidth 高发 | SFU 单实例 | SFU 级联 + Simulcast |
| 跨地区用户 RTT > 200ms | 单数据中心 SFU | 多区域 SFU + 媒体路由 |
| 直播观众 > 1000 | SFU | SFU + CDN 混合 |
| 合规要求统一画面录制 | SFU | SFU + 旁路合流 |
| 端 CPU < 20% 余量 | SFU 多路解码 | SFU + Simulcast 降阶 / MCU |
9. 混合拓扑:现实里更常见
真实生产系统几乎都是混合拓扑:
要点:
- 互动用户走 WebRTC SFU,延迟 < 200ms
- 观看用户走 CDN,延迟 1-5s 可接受、成本低
- 录制走旁路合流,不影响实时链路
- 跨区域用 SFU 级联而不是客户端跨区直连
10. 反模式
| 反模式 | 后果 | 替代 |
|---|---|---|
| 4 人会议硬上 Mesh | 上行带宽爆炸 | SFU |
| 上 SFU 但不开 Simulcast | 弱网用户拖慢全场 | 默认开 q/h/f 三层 |
| MCU 当万能合流器 | 成本高、延迟差 | 仅在端能力受限或合规需求时用 |
| 直播万人扛 SFU | 成本远高于 CDN | 互动 SFU + 观看 CDN |
| 跨地区用同一个 SFU | RTT 高,体验差 | 多区域 + 级联 |
| Mesh 没考虑 N²信令 | 信令服务被打爆 | 客户端发布订阅模型清理 |
| SFU 没接 TWCC | 拥塞控制失效 | RTP extmap 加 transport-wide-cc |
| 录制硬塞实时链路 | 实时帧延迟跳变 | 旁路 / 异步合流 |
11. 选型 checklist(直接抄)
- 业务最大房间人数 N?
- 是否需要服务端录制 / 合规?
- 是否需要 RTMP / SIP / CDN 互通?
- 端到端加密是否硬性要求?
- 用户是否跨大区?
- 单房间互动者 vs 观看者比例?
- 预算更敏感的是带宽还是 CPU?
- 是否已有可观测体系支撑拓扑切换决策?
回答清楚以上 8 题,拓扑就基本定了。
12. 权威资料
- WebRTC Architecture & Topologies (Tsahi Levent-Levi): https://bloggeek.me/webrtc-multiparty-architectures/
- IETF RFC 7667 RTP Topologies: https://www.rfc-editor.org/rfc/rfc7667
- mediasoup Architecture: https://mediasoup.org/documentation/v3/mediasoup/design/
- LiveKit Architecture: https://docs.livekit.io/home/get-started/intro-to-livekit/
- Janus Gateway concepts: https://janus.conf.meetecho.com/docs/
- 核对日期:2026-06-22