SFU 架构:选择转发单元实现多人音视频
什么是 SFU
在多人实时音视频场景中,常见的服务器架构有三种:Mesh(网状)、MCU(多点控制单元)和 SFU(Selective Forwarding Unit,选择转发单元)。SFU 是目前最主流的架构,它不进行音视频的混合、转码,而是作为“智能路由”,将每个参与者的媒体流有选择地转发给其他参与者。相比 Mesh 架构,SFU 大幅减轻了客户端的上行带宽压力;相比 MCU,SFU 避免了服务端的编解码计算开销,延迟更低,扩展性更好。
SFU 的工作原理
SFU 的核心功能可以概括为:接收流 → 决策转发 → 分发流。服务端对每一路进入的媒体流进行解析,获取其编码信息(如分辨率、码率、帧率、关键帧位置等),再根据每个订阅者的网络状况、终端能力、订阅需求,进行有选择的转发。流本身的内容不改变,因此 SFU 不需要进行耗时的解码和重新编码,只需在可选的场景下进行包缓存、纠错或简单的封装调整。
媒体流的基本单元:轨道
在 WebRTC 中,一个音视频通话往往由多条媒体轨道(MediaStreamTrack)组成,例如一条音频轨道、一条或多条视频轨道(摄像头、屏幕分享等)。SFU 以轨道为单位进行管理,每个轨道的编码独立,服务端能够实现精细化的转发控制。例如,用户可以只订阅对方的高清视频轨道而不接收其音频,或者在小窗模式下接收低分辨率轨道,全屏时切换到高分辨率轨道。
推流与拉流流程
一次典型的 SFU 通话流程如下:
- 推流阶段:客户端通过 ICE 协商与服务端建立 PeerConnection,将采集到的音视频数据编码后通过 SRTP 推送到 SFU。
- 信令与订阅:业务服务通过自定义信令告知 SFU,哪些参与者需要接收哪些轨道。SFU 内部建立订阅关系映射。
- 拉流阶段:SFU 根据订阅关系,将当前缓存的媒体包通过已有的下行 PeerConnection 发送给各个接收方。下行流可以是独立的一条 PeerConnection 传输多个轨道,也可以按轨道粒度创建多个对等连接,具体取决于实现。
缓存与带宽自适应
SFU 通常会在内存中为每个轨道维护一个短暂的包缓冲区(例如 2-4 秒的环形缓冲区),用于重传恢复、关键帧请求和码率自适应。当接收方报告弱网时,SFU 可通过以下手段优化传输质量:
- 发送端带宽估计(TCC + REMB):根据接收端反馈的丢包和延迟信息,向发送端请求降低码率,或者 SFU 自身在转发前丢弃部分非关键帧包。
- 分层视频编码(SVC / Simulcast):发送端可同时编码多个不同质量层(如 180p、360p、720p),SFU 根据各接收方的带宽状况,仅转发最适合的一个或几个层。这避免了在服务端进行转码,同时做到按需投放。
- 关键帧请求(PLI/FIR):当订阅者刚加入或丢包严重需要刷新画面时,SFU 主动向发送端请求新关键帧。
SFU 的核心架构与关键模块
一个生产级 SFU 内部一般包含以下模块:
信令桥接与房间管理
SFU 本身不处理业务逻辑,它需要一个信令服务进行房间创建、加入/离开、轨道发布与订阅状态的维护。信令服务通过内部 API(如 gRPC、消息队列)将参与者的 JOIN/LEAVE、Publish/Unpublish、订阅变更等事件实时同步给 SFU,使其能够动态调整转发拓扑。
媒体引擎与传输层
SFU 的媒体引擎负责处理 DTLS-SRTP 协商、ICE 连通性检查、RTP/RTCP 包的解析与构造。对于每个上行流,引擎会维护 SRTP 解密状态、RTP 序列号连续性检查、nack 重传队列等;对于每个下行流,引擎进行 SRTP 加密、包发送调度以及 RTCP 反馈的收集与转发。
订阅与转发引擎
这是 SFU 的智能核心。引擎以“订阅关系表”为驱动,表结构可描述为:(发送者, 轨道ID) → [接收者列表]。当某个上行轨道的 RTP 包到达后,引擎立即查找该轨道的所有接收者,为每个接收者复制包并推送到相应的下行发送队列。为了提高效率,可在网络层做零拷贝转发(如内核旁路),并采用多线程/协程架构避免队头阻塞。
统计与质量监控
SFU 需要为每个轨道、每个订阅建立实时的统计信息,例如入站码率、出站码率、丢包率、往返时间、帧率等。这些统计不仅用于内部自适应算法,也会回调给上层业务,用于计费、通话质量报表和问题追踪。
SFU 的部署与扩展
由于 SFU 是计算和带宽密集型服务,需要支持大规模并发,必须考虑水平扩展方案。常见方式包括:
- 地域分布式 + DNS/Anycast:在不同地域部署 SFU 集群,用户就近接入,降低端到端延迟。
- 级联 SFU:在超大型会议中,单机 SFU 可能无法容纳全部参与者。此时可将房间拆分为多个子区,每个子区由一台 SFU 负责,子区之间通过级联链路交换媒体的子集。例如只转发少数几位主讲人的音频和视频,避免全量复制。
- 媒体与信令分离:信令服务可以独立于 SFU 进行无状态水平扩展,SFU 本身则作为有状态服务通过一致性哈希分配房间。
常见开源 SFU 选型
| 项目 | 语言 | 特点 |
|---|---|---|
| Mediasoup | C++ / Node.js | 高性能、模块化设计、丰富的 API 控制,支持 Simulcast 和 SVC,是目前最为广泛使用的新一代 SFU。 |
| Janus | C | 轻量级、插件化架构,除了 SFU 还支持 MCU 等模式,适合定制化需求。 |
| LiveKit | Go | 全栈解决方案,提供 SDK、服务端和云服务,易于快速搭建实时音视频应用。 |
| Ion | Go | 纯 Go 实现,基于 Pion WebRTC 库,适合云原生部署和自定义扩展。 |
自研 SFU 的注意事项
如果选择自研 SFU,需要重点关注以下点:
- RTP 包转发的正确性:必须正确处理 RTP 头部扩展、序列号与时间戳重写、SSRC 冲突解决。通常在转发时,SFU 不修改 SSRC,但接收端可能会同时订阅多个源,此时需要上行方向使用不同的 SSRC 或利用 MID/RID 进行轨道标识。
- 时间同步与延迟控制:音视频同步依赖于 RTCP 发送方报告中的 NTP 时间戳。SFU 转发的音频和视频流若来自同一源,应保证不同轨道的 RTP 时间戳对齐不被破坏。
- 安全与权限:防止未授权的订阅或伪造信令入侵。SFU 需要与信令联动,校验每个订阅请求的合法性(如房间票据、参与者权限),并支持端到端加密场景下的密钥管理(如 Insertable Streams 或 SFrame 方案)。
总结
SFU 架构在实时音视频领域凭借其低延迟、高扩展性和较低的服务端成本,已成为多人通话、互动直播的基础设施。理解其选择性转发的核心思想、媒体轨道粒度管理以及带宽自适应机制,是搭建或选型实时通信系统的关键一步。借助成熟的开源方案(如 Mediasoup)可以快速落地,但对于超大规模或特殊场景,仍需深度定制其转发逻辑与部署拓扑。