SFU横向对比
SFU 是 WebRTC 多人架构的核心。本文不重复每个项目的官网描述,而是用工程视角回答一个问题:
"如果今天要从零开始做实时音视频产品,我应该选哪个 SFU?为什么?"
涵盖语言、性能、协议支持、SDK 完整度、Simulcast/SVC、文档质量、社区活跃度、商业模式、推荐场景。
1. 选型矩阵(一张表看懂)
| 维度 | mediasoup | LiveKit | Janus | Pion | Jitsi Videobridge (JVB) |
|---|---|---|---|---|---|
| 语言 | Node.js + C++ Worker | Go | C | Go(库) | Java(Kotlin 趋势) |
| 架构形态 | 库(Lib,需自己包房间) | 完整服务(Server+Cloud+SDK) | 模块化插件 Server | 协议库 + 自组装 | 完整服务(Jicofo + JVB) |
| 核心强项 | 灵活、低层可控 | 工程化最完整、SDK 全栈 | SIP/老协议互通、插件丰富 | 纯 Go、零依赖、WHIP/WHEP 友好 | 端到端会议方案 |
| 核心弱项 | 没房间逻辑、要自研 | 部分定制需改源码 | 文档老、API 陈旧 | 不是开箱 SFU,要自己拼 | 与 Jitsi 框架耦合重 |
| Simulcast | ✅ 原生 | ✅ 原生 | ✅ 部分插件 | ✅ 原生 | ✅ 原生 |
| SVC(VP9/AV1) | ✅ VP9 SVC、AV1 SVC | ✅ VP9/AV1 | ⚠️ 部分插件 | ✅(手写) | ✅ VP9 K-SVC |
| TWCC / REMB | ✅ | ✅ | ✅ | ✅ | ✅ |
| WHIP/WHEP | 社区扩展 | ✅ 内置 | ✅ 插件 | ✅ 一等公民 | ⚠️ 实验 |
| SIP 互通 | ❌(需自接 Janus / FS) | ✅ SIP 网关 | ✅ 原生强项 | ⚠️ 自写 | ✅ Jigasi |
| 录制 | 自接 GStreamer/FFmpeg | ✅ Egress 服务 | ✅ recorder 插件 | 自写 | ✅ Jibri |
| Insertable Streams / E2EE | ✅(支持 frame 透传) | ✅ E2EE 内置 | ⚠️ | ✅ | ⚠️ |
| 官方 Web SDK | 第三方居多 | ✅ 完整 | mock/官方 demo | ❌ | ✅ |
| iOS/Android SDK | 第三方 | ✅ 官方 | ⚠️ Demo | ❌ | ✅ |
| Unity/Flutter SDK | ❌ | ✅ | ❌ | ❌ | ⚠️ |
| k8s/部署 | 自己拼 | ✅ Helm/Operator | 手工 | 手工 | Helm |
| 商业模式 | MIT 开源 + 公司 Versatica 顾问 | Apache 2 + LiveKit Cloud | 严格双协议(GPL/商) | MIT 完全开放 | Apache 2 + 8x8 商业 |
| GitHub Stars(2026-06) | ~10k | ~13k+ | ~9k | ~16k(库) | ~3k |
| 典型用户 | Discord(早期)、Mirotalk | OpenAI Realtime API、Spot AI、Slack Huddles | FOSDEM、众多电信项目 | LiveKit/ION/Galene 等基于它 | Jitsi Meet、8x8、Element Call |
| 学习曲线 | 中-高 | 低 | 高 | 高 | 中 |
| 推荐场景 | 自研 SaaS、需要极致定制 | 90% 业务首选 | VoIP/SIP 互通、电信网 | 自研直播/网关、定制深 | 内部会议系统、一次部署省事 |
2. mediasoup:库化 SFU 的代表
2.1 工程视角
mediasoup 不是一个开箱即用的 Server,而是一个库:你拿它的 Worker / Router / Transport / Producer / Consumer API 自己拼业务。它是 Versatica 公司维护,作者 Iñaki Baz Castillo 同时是 JsSIP / SipDroid 作者。
为什么选:
- 灵活度天花板。Producer/Consumer 模型是 SFU 业界事实标准
- C++ Worker 性能扎实,单 Worker 能扛 ~1500 路 720p
- 透明 SVC/Simulcast 转发,不偷偷压缩或丢层
- Insertable Streams 支持极好,做 E2EE 容易
为什么不选:
- 没房间,没鉴权,没录制,没 SDK。所有这些你都要自己写
- 中型团队(< 5 人)很难驾驭。它把"难"摆在面上,不像 LiveKit 帮你藏起来
- Node.js 主进程 + C++ Worker 跨进程通信,调试链路较长
2.2 代码示例(创建房间转发)
import * as mediasoup from 'mediasoup';
// 1. 启动 Worker
const worker = await mediasoup.createWorker({
rtcMinPort: 40000,
rtcMaxPort: 49999,
logLevel: 'warn',
});
// 2. 创建 Router(一个 Router 等于一个房间)
const router = await worker.createRouter({
mediaCodecs: [
{ kind: 'audio', mimeType: 'audio/opus', clockRate: 48000, channels: 2 },
{ kind: 'video', mimeType: 'video/VP8', clockRate: 90000 },
{ kind: 'video', mimeType: 'video/VP9', clockRate: 90000, parameters: { 'profile-id': 2 } },
{ kind: 'video', mimeType: 'video/AV1', clockRate: 90000 },
],
});
// 3. 给每个客户端创建 WebRtcTransport
const transport = await router.createWebRtcTransport({
listenIps: [{ ip: '0.0.0.0', announcedIp: '203.0.113.10' }],
enableUdp: true,
enableTcp: true,
preferUdp: true,
initialAvailableOutgoingBitrate: 1_000_000,
});
// 4. 客户端发布 → 服务端 produce
const producer = await transport.produce({
kind: 'video',
rtpParameters,
paused: false,
});
// 5. 其他客户端订阅 → 服务端 consume
const consumer = await otherTransport.consume({
producerId: producer.id,
rtpCapabilities: otherClient.rtpCapabilities,
paused: true,
});
要点:每一对都要走 Producer/Consumer 显式建立。适合订阅关系明确的产品,不适合"广播给全房间"懒模型。
2.3 失败的样子
- 房间逻辑自己写,N 个 bug 都能复现:发言者切层抖动、订阅时序错乱、关流没回收 transport
- 升级 Node 版本踩 native binding 坑
3. LiveKit:工程化最完整的全家桶
3.1 工程视角
LiveKit 是 Go 写的、自带 Server + 全平台 SDK + Cloud 服务的"开箱即用"SFU 平台。OpenAI 2024 年的 Realtime API 实时语音互动选了它,是当下增长最快的项目。
为什么选:
- 90% 业务诉求开箱即用:房间、token、ACL、录制(Egress)、互通(Ingress/SIP/RTMP/WHIP)
- 全栈 SDK:Web/iOS/Android/Flutter/React Native/Unity/Unreal,文档清晰
- LiveKit Cloud 可直接对照托管,本地自建做不动可以无缝迁
- 内置 E2EE、自动 Simulcast/SVC 调度、Adaptive Stream
为什么不选:
- 抽象层略厚,深定制要改源码(Go 代码组织合理但量不少)
- 默认强绑定它的 SDK 协议(基于 protobuf 的 RTC Engine),自定义客户端要重写
- 商业版 LiveKit Cloud 用得多了会和开源版本有功能差距感
3.2 部署示例
# livekit.yaml
port: 7880
rtc:
tcp_port: 7881
udp_port: 7882
use_external_ip: true
keys:
APIxxxxxxxxxxxx: secretxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
redis:
address: redis:6379
turn:
enabled: true
domain: turn.example.com
tls_port: 5349
udp_port: 3478
ingress:
rtmp_base_url: rtmp://ingress.example.com/x
egress:
insecure: false
s3:
access_key: AKIA...
secret: ...
region: ap-northeast-1
bucket: livekit-recordings
// 服务端签发 token(go-jwt)
package main
import (
"github.com/livekit/protocol/auth"
"time"
)
func makeToken(room, identity string) (string, error) {
at := auth.NewAccessToken(apiKey, apiSecret).
AddGrant(&auth.VideoGrant{
Room: room,
RoomJoin: true,
CanPublish: boolPtr(true),
CanSubscribe: boolPtr(true),
}).
SetIdentity(identity).
SetValidFor(time.Hour)
return at.ToJWT()
}
3.3 失败的样子
- 没看
RoomService/Egress的并发限制,录制任务堆积 - 自己加协议把核心 RTC Engine 改坏了,升级版本困难
- 用 LiveKit Cloud 然后又部分回迁自建,跨账号配额对不上
4. Janus:插件式老兵
4.1 工程视角
Janus 是 Meetecho(IETF 主力贡献者之一)维护的 C 语言 SFU。结构是核心 + 插件:videoroom(SFU)、streaming(直播)、sip(SIP 网关)、recordplay(录制回放)等等。它的 SIP/PSTN 互通能力是任何对手都比不上的。
为什么选:
- VoIP / SIP / 老电信网络互通是它的看家本领
- 插件模型让"录像 → 流播 → 多路转推"用同一个 Janus 进程串起来
- C 语言 + libnice,资源占用极低
为什么不选:
- API 偏老派(HTTP / WebSocket / Unix Socket / RabbitMQ 多入口),上手难
- 文档是 Doxygen 直出,对新手不友好
- 插件之间数据流非常隐式,调试要看源码
4.2 启用 videoroom 插件示例
{
"janus": "create",
"transaction": "tx-1"
}
{
"janus": "attach",
"plugin": "janus.plugin.videoroom",
"session_id": 1234
}
{
"janus": "message",
"transaction": "tx-2",
"body": {
"request": "create",
"room": 1000,
"publishers": 8,
"videocodec": "vp9,h264",
"video_svc": true,
"transport_wide_cc_ext": true
}
}
4.3 推荐场景
- 任何需要把 WebRTC 和 SIP / RTSP / 老电话网打通的项目
- 已有 FreeSWITCH / Asterisk / Kamailio 体系想加 WebRTC 入口
4.4 失败的样子
- 用 videoroom 当通用 SFU 跑大型互联网产品,遇到坑后社区无法帮你(语境主要是电信)
- 插件参数全靠看源码,升级时悄悄改了行为
5. Pion:纯 Go 的协议库不是开箱 SFU
5.1 工程视角
Pion 是 github.com/pion/webrtc 这一系列纯 Go 实现的 WebRTC 协议库。它本身不是 SFU,但很多 SFU/网关项目都用它做底层(如 ION、Galene、AWS Kinesis Video WebRTC、Cloudflare Calls 早期、LiveKit 部分组件)。
为什么选:
- 纯 Go、零 cgo 依赖、跨平台编译极方便
- WHIP/WHEP / DataChannel / 自定义 RTP 处理一等公民
- 适合做"我要一个 WebRTC 入站/出站网关"而不是"我要一个会议系统"
为什么不选:
- 不提供房间、订阅、信令、SDK
- 性能在大规模 SFU 场景比 mediasoup 的 C++ Worker 略弱
- 学习成本高,要懂 RTP / RTCP / DTLS / SRTP 全栈
5.2 用 Pion 写一个最小 WHIP 入口
package main
import (
"io"
"net/http"
"github.com/pion/webrtc/v4"
)
func whipHandler(w http.ResponseWriter, r *http.Request) {
offer, _ := io.ReadAll(r.Body)
pc, _ := webrtc.NewPeerConnection(webrtc.Configuration{})
pc.AddTransceiverFromKind(webrtc.RTPCodecTypeVideo,
webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionRecvonly})
pc.AddTransceiverFromKind(webrtc.RTPCodecTypeAudio,
webrtc.RTPTransceiverInit{Direction: webrtc.RTPTransceiverDirectionRecvonly})
pc.OnTrack(func(track *webrtc.TrackRemote, _ *webrtc.RTPReceiver) {
// 转发到 SFU 内部总线 / 写文件 / 转 RTMP
})
pc.SetRemoteDescription(webrtc.SessionDescription{
Type: webrtc.SDPTypeOffer,
SDP: string(offer),
})
answer, _ := pc.CreateAnswer(nil)
gather := webrtc.GatheringCompletePromise(pc)
pc.SetLocalDescription(answer)
<-gather
w.Header().Set("Content-Type", "application/sdp")
w.Header().Set("Location", "/whip/session/123")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(pc.LocalDescription().SDP))
}
func main() {
http.HandleFunc("/whip", whipHandler)
http.ListenAndServe(":8080", nil)
}
50 行 Go 拿到一个能用的 WHIP 网关,是 Pion 的甜点。
5.3 失败的样子
- 当 SFU 用,结果发现要自写订阅、Simulcast 选层、TWCC 反馈逻辑
- 没读懂 RTP/RTCP,丢包 / NACK / PLI 都靠默认值跑
6. Jitsi Videobridge:开会场景的成熟方案
6.1 工程视角
JVB 是 Jitsi Meet 后端的 SFU,Java/Kotlin 实现。配套有 Jicofo(焦点控制)、Jigasi(SIP 网关)、Jibri(录制)、Prosody(XMPP 信令)。是一个完整会议套件,不是一个 SFU 库。
为什么选:
- 全套部署有 Helm chart 和 Docker compose,1 小时就能跑出 Jitsi Meet
- 8x8 商业产品的同源开源代码,企业级稳定
- VP9 K-SVC、Last-N、SSRC 重写、端点优先级等会议导向能力强
为什么不选:
- 跟 XMPP 信令绑得很死,自定义信令成本高
- Java 栈对很多团队是负担
- 想把它嵌入"自家产品的一个模块"非常麻烦
6.2 推荐场景
- 内部会议系统,求一次部署省事
- 教育 / 在线课堂,对会议默认行为依赖度高
7. 性能对比的真相
跑分容易得出误导结论。下面给一个经验级对比(同硬件 8C16G、Linux、千兆网卡):
| 指标 | mediasoup | LiveKit | Janus | Pion 自组装 | JVB |
|---|---|---|---|---|---|
| 单实例峰值 720p 转发路数 | ~1500 | ~1200 | ~1000 | ~600-800 | ~800 |
| 单路 CPU 开销(μs/包) | 低 | 低-中 | 低 | 中 | 中 |
| 调度延迟波动 | 小 | 小 | 小 | 中 | 中 |
| 内存占用(千路时) | < 1.5 GB | < 2 GB | < 1 GB | 视实现 | 2-3 GB |
结论:差距在 1.5-3 倍区间,不是数量级。真正决定性能的是有没有正确开启 Simulcast/SVC、TWCC、RTX,而不是底层 SFU 选型。
8. 决策树
9. 工程对比维度补充
9.1 升级与版本兼容
- mediasoup:major 版升级 API 偶有破坏(v2 → v3 是大改)。每年 1-2 个 major
- LiveKit:Server 与 SDK 的版本强相关。混用版本会出协议不兼容
- Janus:升级保守,老版本能跑很久
- Pion:包级别版本独立,需要锁版本
- JVB:跟 Jicofo 必须同步升级
9.2 学习资源
| 项目 | 官方文档 | 社区 | 入门 demo |
|---|---|---|---|
| mediasoup | mediasoup.org ✅ | Discourse | mediasoup-demo |
| LiveKit | docs.livekit.io ✅✅ | Slack | livekit-meet, agents |
| Janus | Doxygen 风格 ⚠️ | Google Group | janus-gateway/html |
| Pion | godoc + examples | Slack 活跃 | pion/example-webrtc-applications |
| JVB | jitsi.org/community ⚠️ | Forum | jitsi-meet docker |
9.3 商业风险
- mediasoup:MIT,零商业风险。Versatica 提供顾问服务
- LiveKit:Apache 2,零商业风险。但自建 vs Cloud 有功能差距倾向
- Janus:双协议(GPLv3 + 商业)。GPL 要传染源码,部分公司不能接受
- Pion:MIT
- JVB:Apache 2
10. 常见误判
| 误判 | 现实 |
|---|---|
| "C++ 一定比 Go 快" | mediasoup 是 Node + C++ Worker,主控仍在 Node,瓶颈往往在 IPC |
| "Janus 老所以一定差" | 它在 SIP/电信场景仍然是无敌的 |
| "Pion 不能扛大流量" | LiveKit、Cloudflare 都用它的协议层支撑高并发 |
| "LiveKit 太抽象不灵活" | 大多数业务诉求 LiveKit 都能配出来,不要为 1% 的需求选错栈 |
| "MCU 比 SFU 强大" | 是另一种取舍,不是上下位关系 |
11. 反模式
| 反模式 | 后果 | 替代 |
|---|---|---|
| 同时用三个 SFU "兜底" | 协议、SDK、监控全要复制三套 | 选一个主栈 |
| 选 Pion 然后期待开箱 | 自研工作量超预期 3-5 倍 | 选 LiveKit / mediasoup |
| 选 mediasoup 但只有一个新人开发 | 几个月做不出 MVP | 选 LiveKit |
| 选 LiveKit 然后把核心引擎改成 fork | 升级困难 | 通过插件 / Server-side Agent 扩展 |
| 选 Janus 但不用它的 SIP 互通能力 | 浪费它最强的肌肉 | 用 mediasoup/LiveKit |
| 选 JVB 然后想嵌进自家 SaaS | 信令耦合 XMPP,工作量巨大 | 选 LiveKit |
12. 给不同团队的速选
| 团队画像 | 推荐 |
|---|---|
| 创业公司 / 1-3 人后端 | LiveKit |
| 大厂自研产品 / 10+ 人 | mediasoup 或 fork LiveKit |
| 电信 / VoIP 互通公司 | Janus(+ 必要时 LiveKit 配合) |
| 直播平台 / 网关方向 | Pion + 自研 |
| 内部 IT 会议系统 | Jitsi Meet 一键部署 |
13. 权威资料
- mediasoup: https://mediasoup.org/
- mediasoup design: https://mediasoup.org/documentation/v3/mediasoup/design/
- LiveKit docs: https://docs.livekit.io/
- LiveKit GitHub: https://github.com/livekit/livekit
- Janus Gateway: https://janus.conf.meetecho.com/docs/
- Janus videoroom 插件文档: https://janus.conf.meetecho.com/docs/videoroom.html
- Pion: https://pion.ly/
- Pion examples: https://github.com/pion/example-webrtc-applications
- Jitsi Videobridge: https://github.com/jitsi/jitsi-videobridge
- Jitsi Meet handbook: https://jitsi.github.io/handbook/
- 8x8 / Jitsi Architecture: https://jitsi.org/blog/
- 核对日期:2026-06-22