直播系统设计

本文系统设计一个直播系统:需求澄清与量级估算、推流接入与鉴权(RTMP/SRT、推流鉴权、断流检测与重连)、转码与低延迟分发(多码率阶梯、HLS/LL-HLS/WebRTC 选型、CDN 边缘回源)、连麦与信令(SFU 架构、房间状态同步)、弹幕与消息风暴(长连接广播、削峰与降级),并给出架构图、数据表与容量规划。

直播是「实时性、规模、互动」三重压力叠加的系统:主播端一路推流,几十万观众同时拉流,还要支持连麦、弹幕、送礼这些实时互动。它和点播最大的区别是——内容在产生的那一刻就要被分发出去,没有转码完再发布的缓冲窗口,任何环节的延迟都会直接反映在观众体验上。本文按照系统设计面试的标准答题结构,设计一个生产级的直播系统。

一句话:直播系统的两条主线是「低延迟分发」与「高并发互动」——推流链路决定了延迟下限,互动链路决定了规模上限,两者对基础设施的要求截然不同。

一、需求澄清与量级估算

1.1 需求澄清

面试官给出题目「设计一个直播系统」后,先通过提问明确边界:

  • 直播类型:秀场直播、游戏直播、电商直播、教育直播、还是低延迟互动直播(连麦 PK)?类型决定延迟要求。
  • 延迟要求:普通秀场可接受 35 秒;电商直播希望 13 秒;连麦 PK 要求 400ms 以内。延迟要求直接决定协议选型。
  • 互动能力:弹幕、点赞、送礼、连麦、连麦 PK、观众上麦,支持到哪一层?
  • 规模:单房间峰值观众数?是「少量大房间」(如明星演唱会百万在线)还是「大量小房间」(如秀场几千房间各几百人)?
  • 清晰度:支持几档码率?是否需要 1080p60?
  • 内容安全:是否需要实时审核(鉴黄、涉政)、延迟几秒内可封禁?
  • 录制与回放:是否要边播边录、结束后生成回放?

1.2 量级估算

以一个中等直播平台为例:

日活观众:          3000 万
同时在线房间:      5 万(秀场为主)
单房间平均观众:    60 人,头部房间可达 10 万+
峰值同时观看:      500 万
主播推流码率:      4 Mbps(1080p)
单主播上行带宽:    5 万 × 4Mbps = 200 Gbps(入)
观众下行带宽:      500 万 × 平均 2Mbps = 10 Tbps(出,靠 CDN 分摊)
弹幕 QPS:          500 万在线 × 人均 0.2 条/分钟 ≈ 1.7 万条/秒(峰值 ×5 ≈ 8.5 万/秒)
礼物消息 QPS:      峰值 2 万/秒(大促/大主播带货时)
连麦房间:          约 1% 房间同时连麦 → 500 个并发连麦房

关键结论:下行带宽是最大的成本项(10 Tbps 必须靠 CDN 分摊),弹幕是最大的 QPS 来源(8.5 万/秒),而推流上行的房间数相对稳定(5 万路)。三个数字指向三套不同的技术栈:推流用长连接接入层、分发用 CDN、弹幕用长连接广播层。

二、高层架构设计

  主播 ──RTMP/SRT推流──▶ ┌────────────────┐
                         │ 推流接入集群     │  鉴权 / 断流检测
                         │ (边缘节点)       │
                         └───────┬────────┘
                                 ▼
                         ┌────────────────┐
                         │ 转码集群         │  多码率 / 实时审核
                         │ (GPU + 审核)     │  截帧送审
                         └───────┬────────┘
                                 ▼
                         ┌────────────────┐
                         │ 源站 (Origin)    │  切片 / 封装
                         │ HLS/DASH/FLV    │
                         └───────┬────────┘
                                 ▼
                    ┌────────────────────────┐
                    │ CDN 边缘节点(回源拉流) │
                    └───────────┬────────────┘
                                ▼
                         ┌────────────────┐
                         │ 观众播放器       │  HLS/FLV/WebRTC
                         └───────┬────────┘
                                 │ 弹幕/礼物/连麦信令
                                 ▼
                         ┌────────────────┐
                         │ 互动长连接集群   │  弹幕广播 / 房间状态
                         │ (WebSocket)     │
                         └───────┬────────┘
                                 ▼
                         ┌────────────────┐
                         │ 连麦信令 (SFU)   │  WebRTC 媒体转发
                         └────────────────┘

四条关键链路:

  1. 推流链路:主播 RTMP/SRT 推流到接入节点,鉴权通过后转发到转码集群。
  2. 转码链路:转出多档码率并实时截帧送内容审核,审核通过才允许分发。
  3. 分发链路:源站切片封装成 HLS/FLV,CDN 边缘回源拉流并缓存,观众就近拉取。
  4. 互动链路:观众通过 WebSocket 长连接发弹幕、礼物,服务端广播到同房间所有连接;连麦走 WebRTC SFU。

三、核心组件设计

3.1 推流接入与鉴权

协议选型:

RTMP:    老牌直播协议,基于 TCP,延迟 1~3 秒,主播端支持最广,但浏览器已不支持(需 Flash 或转封装)
SRT:     基于 UDP,抗丢包强,适合弱网推流,延迟 200~500ms,OBS 已支持
RTSP:    安防/IPC 常用,直播平台少用
WebRTC:  浏览器直接推流,延迟 < 500ms,但码率与稳定性弱于 SRT

实践组合:主播端 RTMP 为主(兼容性最好),弱网/移动端用 SRT,浏览器开播用 WebRTC。接入层要同时支持多协议,统一转成内部格式。

推流鉴权:防止盗推(别人拿你的推流地址乱推)与盗播(未授权拉流)。

推流鉴权(URL 签名):
  推流地址 = rtmp://push.example.com/live/{stream_key}?txSecret={md5}&txTime={expire}
  txSecret = MD5(secret_key + stream_key + txTime_hex)
  接入节点校验:重算 txSecret 是否匹配、txTime 是否过期

拉流鉴权(防盗链):
  播放地址 = https://cdn.example.com/live/{stream_key}.m3u8?auth_key={sign}&expire={ts}
  CDN 边缘校验签名,防止第三方站点盗用你的带宽

断流检测与重连:

class StreamSession:
    def on_publish(self, stream_key, conn):
        if not verify_sign(stream_key, conn.query):
            conn.close(); return
        self.sessions[stream_key] = {"conn": conn, "last_frame": now()}

    def heartbeat_check(self):
        """定时扫描:超过 5 秒没收到媒体帧视为断流"""
        for key, s in list(self.sessions.items()):
            if now() - s["last_frame"] > 5:
                self.on_disconnect(key)

    def on_disconnect(self, key):
        # 通知业务:主播断流 → 房间状态置为「暂离」,保留 30 秒等待重连
        self.sessions.pop(key, None)
        room.set_state(key, "TEMPORARILY_OFFLINE", grace=30)

重连的体验设计:主播网络抖动断流时,不要立刻把房间标记为「已结束」——保留一个宽限期(如 30 秒),期间观众看到「主播网络不稳定」提示而非直接黑屏退出。宽限期内主播重连,无缝恢复;超时才真正结束直播。

推流质量监控:接入节点要持续采集主播端的推流质量(码率、帧率、丢包率、卡顿次数),异常时主动通知主播「当前网络差,建议降低码率」,并支持服务端下发「降码率指令」。这套「客户端上报 + 服务端决策」的模式与 WebRTC 低延迟直播 里的网络自适应完全同源。

3.2 转码与低延迟分发

转码的实时性约束:点播转码可以慢慢来,直播转码必须「边收边转边发」,任何积压都会变成观众端的延迟累积。

实时转码流水线:
  接收帧 → 解码 → [可选:缩放/水印/审核截帧] → 编码 → 切片/封装 → 推送源站
  延迟预算:单次转码延迟必须 < 200ms,否则多档叠加会拖慢整体

关键参数(以 HLS 为例):
  分片时长:2 秒(传统 HLS 是 6~10 秒,直播要更短)
  GOP 长度:2 秒(与分片对齐,保证可无缝切换)
  转码 preset:veryfast / ultrafast(速度优先,画质次之)

多码率阶梯:与点播类似,但直播通常只做 3~4 档(观众带宽有限、切档要快)。

480p  800 kbps
720p  1800 kbps
1080p 3500 kbps

低延迟协议选型:这是直播系统最关键的决策。

协议        延迟        兼容性        成本        适用场景
HLS        6~30 秒     最好(原生)    低(CDN)    普通秀场、录播兼容
LL-HLS     2~5 秒      较好           中          电商直播、互动要求较高
FLV/HTTP-FLV 1~3 秒    需 flv.js      低          国内直播主流
WebRTC     200~500ms   需信令         高(SFU)    连麦、PK、强互动
SRT        200~500ms   需专用播放器    中          专业推流/回传

工程上的常见组合:默认 FLV(1~3 秒)覆盖大多数观众,连麦时切 WebRTC,弱网或旧设备降级 HLS。协议的切换对观众要透明——播放器探测到 WebRTC 不可用就自动回落到 FLV。

CDN 回源与分发:

源站(Origin):     只服务 CDN 边缘的回源请求,不直接对观众
边缘节点:           就近缓存分片,命中率 > 95%
回源策略:
  - 分片文件(.ts/.flv 段):长缓存(如 60 秒,直播分片用完即弃)
  - 清单文件(.m3u8):极短缓存(1~2 秒),否则观众拿不到最新分片
  - 回源请求合并:同一分片的并发回源合并成一个(防回源风暴)
边缘回源失败:       重试其他边缘 / 回上级节点 / 最终回源站

首帧优化:观众点进直播间最在意「多久出画面」。优化手段包括:CDN 预取(进房间前先拉清单)、起始档位选择(按历史带宽直接选合适档位,避免从最低档爬升)、GOP 缓存(边缘缓存一个 GOP,观众进来立刻发一个完整 GOP 出画面)。

3.3 连麦与信令

连麦的本质:把两路(或多路)主播的音视频实时混流后分发给观众。技术选型上,一对一或小房间用 SFU(Selective Forwarding Unit)——服务器只做转发不做混流,客户端各自解码多路。

SFU 架构(以 1v1 PK 为例):
  主播 A ──推流──▶ SFU ──转发──▶ 主播 B
  主播 B ──推流──▶ SFU ──转发──▶ 主播 A
                    │
                    └──合成/分别转发──▶ 观众(看到 A+B 画面)

为什么用 SFU 而不是 MCU(服务器混流):
  SFU:服务器只转发,CPU 开销小,可扩展;客户端解码多路,对观众设备有要求
  MCU:服务器混流成一路,观众只解码一路;但服务器 CPU 开销大,成本高
  直播场景观众端多,通常「主播间 SFU 转发 + 对观众侧做混流」混合使用

信令流程:

1. 主播 A 发起连麦邀请 → 信令服务记录邀请状态
2. 主播 B 接受 → 双方交换 SDP(offer/answer),协商编解码与传输参数
3. 双方通过 ICE 收集候选地址(STUN/TURN),建立媒体通道
4. 媒体经 SFU 转发,观众侧订阅合成流
5. 结束连麦 → 释放媒体通道,房间回到单人直播状态

信令必须可靠有序(用 WebSocket 或可靠消息通道),而媒体走 WebRTC 的 UDP 通道——信令丢了连麦就建不起来,媒体丢几帧只影响画质。这种「控制面可靠、数据面尽力」的分离是所有实时通信系统的通用原则,WebRTC SFU/MCU 架构 里有更深入的拓扑讨论。

房间状态同步:连麦房间的状态(谁在麦上、谁在排队、谁被踢出)是强一致的,不能出现「两个人同时以为自己拿到了麦位」。用「房间状态机 + 乐观锁」管理:

def take_mic(room_id, user_id, expected_version):
    # 条件更新:只有版本号匹配才能抢到麦位
    rows = db.execute(
        "UPDATE live_room SET mic_user=%s, version=version+1 "
        "WHERE room_id=%s AND mic_user IS NULL AND version=%s",
        (user_id, room_id, expected_version))
    if rows == 0:
        raise MicTaken()      # 麦位已被他人占用
    publish_event(MicTaken(room_id, user_id))

连麦的质量保障:连麦对延迟和丢包最敏感。措施包括:优先用 SRT/WebRTC(UDP 抗丢包)、开启 FEC 前向纠错、动态码率(网络差时降码率保流畅)、以及对音频做优先保障(丢视频帧可以,丢音频不行)。

3.4 弹幕与消息风暴

弹幕的规模挑战:一个大主播房间可能有 10 万在线,每人每分钟发 0.2 条弹幕,就是每秒 333 条;峰值(抽奖、大事件)可达每秒上万条。系统要同时做到「低延迟广播」与「不被打垮」。

长连接广播架构:

观众 ──WebSocket──▶ 接入网关(无状态,可水平扩展)
                          │
                          ▼
                    ┌──────────────┐
                    │ 房间消息总线   │  Redis Pub/Sub 或 MQ
                    │ (按 room_id)  │
                    └──────┬───────┘
                           ▼
                    各接入网关订阅自己承载房间的消息 → 推给本地连接

关键点:
  1. 接入网关按 room_id 分片订阅,避免「每个网关订阅所有房间」
  2. 一个房间的连接可能分散在多个网关 → 消息要广播到所有承载该房间的网关
  3. 网关维护「本地房间 → 连接集合」的映射,收到消息后本地扇出

削峰与降级:弹幕是「可丢弃」的——丢掉 10% 的弹幕用户基本无感,但系统不能挂。所以弹幕链路要设计成分层降级:

第 1 层:客户端本地限流(同一用户 1 秒最多发 3 条)
第 2 层:网关限流(单连接 10 条/秒,单房间 1 万条/秒)
第 3 层:服务端采样(房间消息量超阈值时,按比例采样广播,如只广播 50%)
第 4 层:分级广播(大房间只广播「高价值弹幕」:带礼物的、主播回复的、房管的)
第 5 层:熔断(极端情况下关闭弹幕,只保留礼物与系统消息)

「分级广播」是直播弹幕最实用的技巧:10 万人的房间不需要让每个人都看到每一条弹幕,观众看到的弹幕流是「采样 + 优先级」的结果。这与 弹幕系统设计 里的「消息分级 + 采样 + 批量合并」策略一致。

礼物消息不能丢:与弹幕相反,礼物消息涉及金钱,必须可靠、有序、不重复。

礼物链路:
  观众送礼 → 扣款(幂等)→ 生成礼物事件 → 持久化 → 广播特效 + 计入榜单
  要求:
    1. 扣款幂等(幂等键防重复扣)
    2. 事件持久化(用于对账、榜单、主播分成)
    3. 广播可降级(特效可以不显示,但账必须记对)

礼物与弹幕走不同的优先级队列:礼物 P0(可靠 + 优先),弹幕 P2(可丢弃)。这与 消息队列系统设计 里的优先级队列与背压机制同构。

弹幕的存储:弹幕量大且价值低,不需要长期保存(除非录播需要)。做法是「热存内存 + 冷存采样」:内存里保留最近 N 条供新进房间的观众补全历史,落库只存采样后的少量数据(如每 10 秒存 1 条)供事后分析。

内容审核的实时性:弹幕与直播画面都要实时审核。画面审核靠截帧送审(每秒 1~2 帧),弹幕审核靠「敏感词过滤 + 机器分类 + 人工兜底」。审核有延迟,所以策略是「先发后审 + 命中即撤回」——弹幕先广播,审核命中后下发撤回指令删除。这与 内容审核系统设计 的「先放行后拦截 + 可撤回」模型一致。

四、深入权衡

1. 延迟与成本的权衡:延迟越低,成本越高。HLS 延迟 10 秒但 CDN 成本极低(分片可缓存、可分发到最便宜的边缘);WebRTC 延迟 300ms 但要自建 SFU 集群、每路连接都占资源。所以绝大多数观众走 FLV/HLS,只有连麦主播走 WebRTC。

2. 转码档位与成本:多一档码率就多一份转码算力与存储。直播通常只做 3 档,且用 GPU 转码(快),画质略逊于 CPU 但直播可接受。

3. 弹幕的完整性 vs 系统稳定:理论上可以保证「所有弹幕不丢」,但代价是海量长连接与广播带宽。绝大多数平台选择「采样 + 分级」,用少量丢弹幕换取系统在热点事件下不崩。

4. 单房间 vs 多房间的架构差异:大量小房间(秀场)适合「网关按房间分片 + 房间消息总线」;少量超大房间(演唱会)适合「专用集群 + 边缘广播 + 强采样」。两种形态的容量模型完全不同,平台常需同时支持。

5. 内容安全与实时性的冲突:实时审核有延迟,若「审后发」会让直播画面延迟数秒(不可接受),所以只能「先发后审 + 快速封禁」。这意味着必须接受「违规内容可能短暂可见」的风险,用「封禁响应时间」而非「零违规」作为指标。

五、总结

直播系统的设计可以浓缩成四条主线:

  1. 推流接入是入口:多协议(RTMP/SRT/WebRTC)支持 + URL 签名鉴权 + 断流宽限期重连,守住内容源。
  2. 延迟由协议决定:HLS/FLV/LL-HLS/WebRTC 构成延迟-成本谱系,按场景组合选型,观众侧透明降级。
  3. 连麦靠信令与 SFU:控制面(信令)可靠有序,数据面(媒体)尽力而为,房间状态用乐观锁保证麦位唯一。
  4. 弹幕分级、礼物可靠:弹幕可采样可丢弃用分层降级,礼物必须幂等扣款 + 持久化,两条链路优先级截然不同。

延伸阅读:弹幕广播的分级与采样策略见 弹幕系统设计 ;连麦房间的长连接与消息同步见 即时通讯系统设计 ;低延迟媒体传输与 SFU 拓扑见 WebRTC 低延迟直播 与 WebRTC SFU/MCU 架构 ;直播画面的实时审核见 内容审核系统设计 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「design」更多文章

  1. 设计一个视频会议系统(WebRTC SFU)
  2. 设计一个 A/B 测试与实验平台
  3. 设计一个分布式锁服务