思路是:Go 负责控制面 + 高并发服务,媒体面用成熟引擎(SRS/FFmpeg/LL-HLS/WebRTC),两者用消息总线解耦。
1) 明确目标与模式
-
场景:秀场/带货/教育/活动转播
-
协议(入口/出口)
- 入口:RTMP/SRT/WHIP(WebRTC 推)
- 出口:HLS/LL-HLS(大规模分发)、WebRTC(超低延迟互动)、FLV(WebSocket)(兼容)
-
延迟档
- 直播(HLS/LL-HLS):3--20s / 1--3s
- 互动(WebRTC):200--800ms
-
核心指标:并发连接数、首屏时间、端到端延迟、卡顿率、回看可用性、成本/带宽
2) 高层架构(职责划分)
scss
[推流端] ──> [Ingest边缘集群: SRS/Go-RTMP 接入]
│(原始流)
▼
[媒体处理集群]
(转码FFmpeg, 切片LL-HLS/HLS, 录制)
│ ▲
(切片/录制产物) │(鉴权/配额/房间)
▼ │
[对象存储/缓存CDN] │
│ │
[观众端拉流/CDN] <──┘
│
▼
┌────────────────────────────────┐
│ Go 控制面微服务(K8s) │
│ • API Gateway (Gin+JWT) │
│ • 鉴权/用户/房间/计费 │
│ • 会话&在线状态(Redis) │
│ • 信令(WS/gRPC, WebRTC/pion) │
│ • IM/弹幕(WS + NATS/Kafka) │
│ • 任务编排(转码/录制/回看) │
│ • 监控/告警( Prom + Grafana ) │
└────────────────────────────────┘
要点
- 媒体面:尽量选型成熟组件(SRS 做 RTMP/FLV/LL-HLS,FFmpeg 转码,pion/webrtc 做超低延迟)。
- 控制面(Go):房间/信令/鉴权/调度/IM/计费,天然符合 Go 的并发优势。
- 消息总线:Kafka/NATS 解耦媒体事件(推流开始/结束、转码就绪、录制切片完成等)。
3) 关键组件设计(Go 视角)
(A) API Gateway(Gin/Chi)
- 功能:登录鉴权(JWT/OAuth),签发 推流密钥 、播放签名
- 路由:/v1/stream/start、/v1/stream/stop、/v1/room/{id}/join 等
- 反向代理到信令/房间/IM 服务
(B) Ingest 接入(边缘)
- RTMP/SRT/WHIP 接入到最近的边缘节点(可直接用 SRS)。
- 入站鉴权:
?token=xxx
或 RTMP TCUrl 校验 → 调用 Go 鉴权服务。 - 上报事件:推流开始/结束、GOP 时间戳、码率变化 → 通过 NATS/Kafka 发事件。
(C) 转码与打包
-
作业编排服务(Go):
- 消费 "推流开始" 事件 → 分配 FFmpeg 转码 Job(H.264/H.265 + 不同分辨率)
- 输出 HLS/LL-HLS 切片 (.ts/.m4s + .m3u8/part)到 对象存储(S3/OSS)
- 录制/回看:并行写 MP4/FLV 到存储(分段/合并)
-
自适应码流(ABR):生成多 bitrate 的 playlist 并写主索引
(D) WebRTC 互动(Go + pion/webrtc)
-
信令服务(Go, WebSocket):房间内 SDP 交换、ICE/Trickle、踢人/静音等
-
SFU/MCU:
- 轻量可用 pion/webrtc + ion-sfu ;或选 mediasoup/Janus(Go 做信令)
-
旁路录制:SFU 侧录制、或旁路推 RTMP 到转码集群
(E) IM/弹幕/礼物(Go)
- 连接层:WS 长连接(shard/分片),水平扩展
- 消息路由:NATS(低延迟小消息)或 Kafka(海量持久)
- 状态:Redis 保存房间在线、速率控制、礼物打点聚合
- 风控:令牌桶限流、敏感词、刷屏拦截、慢热启动
(F) 播放分发
- HLS/LL-HLS 切片托管到 对象存储 + CDN(边缘缓存)
- WebRTC 走 SFU 节点(按地域调度)
- 低端兼容:HTTP-FLV(SRS 或 Go 自己的 FLV over HTTP)
4) 数据与状态
数据表(简化)
users(id, nickname, role, ...)
streams(id, anchor_id, status, start_at, end_at, ingest_node, playback_urls, ...)
rooms(id, stream_id, title, mode, ...)
orders(id, user_id, coins, ...)
(若有打赏/计费)metrics(stream_id, ts, viewers, bitrate, fps, dropped_frames, ...)
(冷热分层)
即时状态(Redis)
room:{id}:online_set
(在线用户)room:{id}:metrics
(当前码率/延迟)user:{id}:conns
(多端在线)
5) 伸缩与容灾
- K8s :将 Go 微服务、SFU、SRS/转码 Worker 以 部署 + 水平自动扩缩
- 边缘/地域化 :Anycast/GSLB 就近接入 → 通过 调度服务 选择 Ingest/SFU 节点
- 降级策略:WebRTC → LL-HLS → HLS 逐级降级;清晰度自动下探
- 回源保护:CDN 回源限速,切片预热;对象存储多 AZ
6) 可观测性与运维
-
指标:
- 媒体:GOP 间隔、音画编码、关键帧率、端到端延迟、首屏
- 服务:QPS、P99、队列积压、WS 连接数、GC 暂停、出错率
-
链路:OpenTelemetry(gRPC/HTTP/WS 打点)
-
日志:结构化 + 按 stream_id/room_id 关联
-
告警:推流异常、转码失败、切片 5xx、CDN 命中率骤降
7) Go 实战注意点(高并发/低延迟)
-
网络:
- 使用
http1.1 + hijack
做 WS/FLV,或fasthttp
(权衡生态) - 零拷贝 :
io.CopyBuffer
/bytes.Reader
;尽量复用 buffer(sync.Pool
)
- 使用
-
GC/内存:
- 降低临时对象;热点路径手动复用切片
- 监控
GOGC
、GC pause
,大对象分配谨慎
-
并发模型:
- 不要 为每个连接开阻塞 goroutine 写消息;采用 事件循环 + 写队列
- 背压控制:当下游卡顿,丢 B 帧/降码率/限速
-
消息总线 :NATS(轻量实时)+ Kafka(持久重放)组合拳
-
配置热更新:房间白名单、限流阈值、码率档位可动态下发
8) 典型数据流(端到端)
- 主播 OBS → RTMP → SRS(Ingest)
- SRS 通过回调/Hook → Go 鉴权(允许/拒绝)
- SRS 触发 NATS 事件(stream_started)
- 编排服务 下发 FFmpeg Job:转码多码率 + 录制 + 切 HLS/LL-HLS
- 切片落 对象存储,CDN 回源缓存
- 观众:H5/APP 拉 LL-HLS/HLS ;或 WebRTC 走 SFU
- IM/礼物:WS ↔ IM 服务 ↔ NATS 路由
- 结束:收尾任务(合并录制、生成回放、统计结算)
9) 从 MVP 到规模化的演进
- MVP(1--2周):SRS + FFmpeg + HLS,Go 做鉴权/房间/IM,单地域
- 阶段二:LL-HLS 与 WebRTC(pion/ion-sfu),对象存储 + CDN,上监控
- 阶段三:多地域边缘接入、ABR、自适应调度、计费/风控、异地容灾
10) 小示例(Go 片段)
WebSocket 信令/IM 框架骨架
go
// 简化示例:房间广播
type Hub struct {
rooms map[string]map[*Conn]struct{}
pub chan Msg
}
func (h *Hub) run() {
for m := range h.pub {
for c := range h.rooms[m.RoomID] {
select {
case c.out <- m.Data:
default: // 背压:丢包或踢出
close(c.out); delete(h.rooms[m.RoomID], c)
}
}
}
}
推流鉴权回调(SRS)
go
// POST /hooks/on_publish
type PublishReq struct {
App, Stream, Param string `json:"app","stream","param"`
}
func onPublish(w http.ResponseWriter, r *http.Request) {
var req PublishReq; _ = json.NewDecoder(r.Body).Decode(&req)
if !checkToken(req.Param) { w.WriteHeader(403); return }
go bus.Publish("stream.started", req)
w.WriteHeader(200)
}
结论
- 用 Go 做直播 :把 Go 放在 控制面 + 高并发周边服务 ,把 媒体面交给成熟引擎(SRS/FFmpeg/LL-HLS/WebRTC/SFU)。
- 通过 NATS/Kafka 把两边解耦,配合 Redis/CDN/对象存储 实现稳定可扩展。
- 从 MVP → 多地域规模化 逐步演进,过程中最需要盯的就是 延迟、卡顿、首屏、稳定性与成本。