跳到主要内容

SFU横向对比

SFU 是 WebRTC 多人架构的核心。本文不重复每个项目的官网描述,而是用工程视角回答一个问题:

"如果今天要从零开始做实时音视频产品,我应该选哪个 SFU?为什么?"

涵盖语言、性能、协议支持、SDK 完整度、Simulcast/SVC、文档质量、社区活跃度、商业模式、推荐场景。

1. 选型矩阵(一张表看懂)

维度mediasoupLiveKitJanusPionJitsi Videobridge (JVB)
语言Node.js + C++ WorkerGoCGo(库)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(早期)、MirotalkOpenAI Realtime API、Spot AI、Slack HuddlesFOSDEM、众多电信项目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、千兆网卡):

指标mediasoupLiveKitJanusPion 自组装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
mediasoupmediasoup.orgDiscoursemediasoup-demo
LiveKitdocs.livekit.io ✅✅Slacklivekit-meet, agents
JanusDoxygen 风格 ⚠️Google Groupjanus-gateway/html
Piongodoc + examplesSlack 活跃pion/example-webrtc-applications
JVBjitsi.org/community ⚠️Forumjitsi-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. 权威资料