1. WebRTC 通话基础架构:P2P 与 SFU/MCU 模型对比、信令服务器角色、NAT 穿透原理
各位同学,咱们今天开篇先聊点基础的。别小看基础,我做了这么多年嵌入式通信,发现大部分线上故障,根子都出在架构理解不透彻上。你连数据怎么流的都不知道,怎么排查问题?
这一章,我带你把 WebRTC 通话的骨架搭起来。说白了,就是三件事:数据怎么传、谁在牵线、怎么穿过防火墙。搞懂这些,后面分析日志你才能一眼看出问题在哪。
1.1 P2P 与 SFU/MCU 模型对比
WebRTC 最核心的理念就是 P2P(点对点)。两个浏览器直接连,不经过服务器转发。好处很明显——延迟低、服务器压力小。但现实很骨感,我遇到过太多场景,P2P 根本打不通。
为什么会这样?因为 NAT 和防火墙。你想想看,公司内网、家庭路由器,层层嵌套,两个设备想直接找到对方,难度不小。这时候就需要服务器来帮忙了。
于是就有了 SFU 和 MCU 两种转发模型。我直接给你画个对比表,一目了然。
| 特性 | P2P (Mesh) | SFU (Selective Forwarding Unit) | MCU (Multipoint Control Unit) |
|---|---|---|---|
| 数据流向 | 每个客户端直接发给其他所有客户端 | 客户端只发一路流给 SFU,SFU 选择性转发 | 客户端发流给 MCU,MCU 混流后发回 |
| 上行带宽 | 高(N-1 路) | 低(1 路) | 低(1 路) |
| 下行带宽 | 高(N-1 路) | 中(按需转发) | 低(1 路混流) |
| 服务器压力 | 无 | 中(转发) | 高(解码+编码) |
| 延迟 | 最低 | 低 | 中(混流引入延迟) |
| 适用场景 | 2-4 人小会议 | 10-50 人会议 | 大型会议、录制 |
我的经验之谈: 在嵌入式设备上,比如摄像头、门铃,我建议优先考虑 SFU。因为嵌入式设备的 CPU 和带宽都有限,P2P 的 Mesh 模型会让设备直接崩溃。我曾经在一个项目里,4 路 P2P 就把一块 ARM Cortex-A7 的芯片干到 100% 占用,画面卡成幻灯片。换成 SFU 后,CPU 占用直接降到 30%。
SFU 是目前最主流的方案。它不混流,只转发。每个客户端只发一路流给 SFU,SFU 再根据订阅关系,把需要的流转发给其他客户端。这样服务器压力小,延迟也低。
MCU 呢?它会把多路流合成一路。比如 4 个人开会,MCU 把 4 个画面拼成一个画面,再发给每个人。好处是客户端解码压力小,但服务器压力大,而且延迟会高一些。现在用的不多了,除非是那种需要录制或转码的场景。
1.2 信令服务器角色
聊完数据怎么传,咱们再说说谁负责牵线搭桥。这个角色就是信令服务器。
信令服务器不传音视频数据,它只传控制信息。比如:
- 谁要加入房间?
- 对方的 IP 地址和端口是多少?
- 用什么编解码器?
- 媒体流怎么同步?
WebRTC 标准里没有规定信令协议,你可以用 WebSocket、HTTP、甚至 MQTT。我个人习惯用 WebSocket,因为它是全双工的,延迟低,适合实时通信。
信令的核心流程,我画了个图,你一看就明白。
流程很简单:
- 客户端 A 加入房间,发个信令给服务器。
- 服务器通知客户端 B,有新用户来了。
- 客户端 B 返回自己的 SDP(会话描述协议)应答。
- 服务器转发给 A。
- 双方开始交换 ICE 候选(后面会讲)。
- 最终建立 P2P 连接,媒体流直连。
注意: 信令服务器如果挂了,整个通话系统就瘫痪了。我曾经在一个项目中,信令服务器用的单点部署,结果半夜宕机,第二天早上才发现。从那以后,我所有项目都强制要求信令服务器做高可用,至少双节点。
1.3 NAT 穿透原理:STUN / TURN / ICE
好,现在问题来了。两个设备都在内网,怎么找到对方?这就是 NAT 穿透要解决的问题。
NAT(网络地址转换)把内网 IP 映射成公网 IP。但不同的 NAT 类型,穿透难度不一样。我直接给你列个表。
| NAT 类型 | 特点 | 穿透难度 |
|---|---|---|
| 完全锥形 NAT | 只要映射过一次,任何外网主机都能通过这个映射访问 | 容易 |
| 限制锥形 NAT | 只有内网主机曾经发过包的目标 IP 才能访问 | 中等 |
| 端口限制锥形 NAT | 只有内网主机曾经发过包的目标 IP:Port 才能访问 | 较难 |
| 对称 NAT | 每次请求都映射不同的端口,且只允许特定目标访问 | 极难(P2P 基本不可行) |
为了解决这个问题,WebRTC 用了 ICE(交互式连接建立)框架。ICE 整合了三种技术:
- STUN(Session Traversal Utilities for NAT):帮你发现自己的公网 IP 和端口。
- TURN(Traversal Using Relays around NAT):当 P2P 打不通时,通过服务器中转数据。
- ICE:统筹管理,尝试所有可能的连接路径,选最优的。
ICE 的流程,我再用一张图给你讲清楚。
ICE 的候选类型有三种:
- host 候选:本机内网 IP,优先级最高。
- srflx 候选:通过 STUN 获取的公网 IP,优先级中等。
- relay 候选:通过 TURN 获取的中继地址,优先级最低。
ICE 会按优先级从高到低尝试。先试 host,不行再试 srflx,最后试 relay。如果 relay 也连不上,那通话就彻底失败了。
避坑指南: 我曾经在一个嵌入式项目中,发现设备总是走 TURN 中继,延迟很高。查了半天,发现是 STUN 服务器地址配错了。设备一直拿不到正确的公网地址,自然打不通 P2P。所以,部署前一定要用工具验证 STUN/TURN 服务器是否可用。我一般用 stunclient 和 turnutils_uclient 来测试。
最后,给你一个简单的 ICE 候选日志示例,方便你以后排查问题。
// ICE 候选收集日志
ICE: New candidate: 192.168.1.100:54321 (host)
ICE: New candidate: 203.0.113.50:54321 (srflx)
ICE: New candidate: 198.51.100.10:3478 (relay)
// 连通性检查
ICE: Checking pair: host(192.168.1.100:54321) <-> host(10.0.0.5:12345)
ICE: Pair succeeded: host(192.168.1.100:54321) <-> host(10.0.0.5:12345)
ICE: Selected pair: host(192.168.1.100:54321) <-> host(10.0.0.5:12345)
看到 Pair succeeded 就说明 P2P 打通了。如果一直显示 Pair failed,最后选了 relay,那就要检查 NAT 类型或者 STUN/TURN 配置了。
好了,这一章的基础架构就讲到这里。记住:P2P 是理想,SFU 是现实,信令是桥梁,ICE 是探路者。后面几章,我们会深入日志分析,到时候这些概念会反复用到。