一、前言
短视频与直播正深刻改变内容传播方式,实时直播系统成为电商、教育、游戏、社交等场景的核心能力。
但其技术挑战也非常大,尤其在推流(主播上传视频)和拉流(观众获取视频)环节,如何支撑百万级并发用户,并保障低延迟、高可用,是系统架构设计的核心课题。
作为一名 Java 开发工程师,本文将从业务需求出发,结合架构设计和关键代码实现,逐步剖析直播系统的推流与拉流关键技术。
二、业务需求分析
1. 基本流程
- 推流:主播端通过 RTMP、SRT、WebRTC 上传音视频流。
- 转码/转协议:将视频转为 HLS、FLV、WebRTC 等适合不同终端的格式。
- 拉流:观众从 CDN 或边缘节点获取直播流播放。
- 控制面:如房间管理、鉴权、在线人数统计、弹幕互动等。
2. 技术挑战
挑战点 | 描述 |
高并发 | 上百万观众同时在线拉流 |
低延迟 | 对直播互动、游戏非常关键(WebRTC 一般 < 1s) |
稳定性 | 网络抖动、节点故障不能影响体验 |
协议支持 | 支持 RTMP、HLS、FLV、WebRTC 等多协议接入和播放 |
弹性扩展 | 突发流量下如何自动扩缩容 |
三、整体架构设计
架构总览图
主播端
↓ (RTMP/SRT/WebRTC)
推流网关 (Nginx-RTMP / Media Server)
↓
转码/转协议处理
↓
内容分发网络 (CDN/边缘节点)
↓
观众端 (H5/APP/小程序)
核心组件说明
组件 | 说明 |
推流网关 | 入口服务,接收主播端上传的音视频流 |
转码器 | 将视频转为不同分辨率、码流,适应不同网络 |
协议转换器 | 支持 RTMP → HLS/FLV/WebRTC 等协议转换 |
CDN/边缘加速 | 缓存热点流,降低主服务器压力 |
控制服务(Java 实现) | 鉴权、房间管理、用户统计、互动控制等 |
四、Java 控制面服务设计
1. 推流鉴权接口
主播推流前需要鉴权,防止非法推流。
请求示例:
POST /api/stream/start
{
"roomId": "1001",
"userId": "u123",
"token": "xxx"
}
鉴权逻辑实现:
@PostMapping("/stream/start")
public ResponseEntity<?> startPush(@RequestBody StreamRequest request) {
if (!authService.isValidToken(request.getUserId(), request.getToken())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("非法推流请求");
}
String streamKey = streamService.generateStreamKey(request.getRoomId(), request.getUserId());
return ResponseEntity.ok(Map.of("streamKey", streamKey));
}
推流地址一般为:
rtmp://push.live.com/live/<streamKey>
2. 拉流地址生成接口
观众进入直播间时,需要获取拉流地址。
@GetMapping("/stream/play")
public ResponseEntity<?> getPlayUrl(@RequestParam String roomId) {
StreamInfo info = streamService.getStreamInfo(roomId);
Map<String, String> urls = Map.of(
"flv", "https://cdn.live.com/live/" + info.getStreamKey() + ".flv",
"hls", "https://cdn.live.com/live/" + info.getStreamKey() + ".m3u8",
"webrtc", "webrtc://cdn.live.com/live/" + info.getStreamKey()
);
return ResponseEntity.ok(urls);
}
3. 在线人数统计(高并发)
使用 Redis 实现实时在线统计:
public void userJoinRoom(String roomId, String userId) {
String key = "live:room:" + roomId + ":online";
redisTemplate.opsForSet().add(key, userId);
redisTemplate.expire(key, Duration.ofHours(1));
}
public int getOnlineUserCount(String roomId) {
String key = "live:room:" + roomId + ":online";
return redisTemplate.opsForSet().size(key).intValue();
}
五、推流与拉流的技术选型
协议对比
协议 | 延迟 | 支持平台 | 使用场景 |
RTMP | 1~3s | PC/移动端 | 主播推流 |
HLS | 5~10s | 全平台 | 大规模分发 |
FLV | 1~3s | PC/H5 | 互动直播 |
WebRTC | <1s | 浏览器 | 实时连麦/互动场景 |
一般策略:推流用 RTMP,拉流根据终端选择 HLS、FLV 或 WebRTC
六、高并发优化策略
1. CDN 边缘分发
- 利用阿里云、腾讯云、七牛等 CDN 进行拉流加速。
- 热门房间使用边缘缓存,减少源站压力。
2. 主播推流入口负载均衡
- 多个推流节点(Nginx + RTMP Module)
- 使用 DNS 轮询或 LVS 做入口负载均衡
3. 分布式房间服务
- 每个直播间作为一个微服务单元部署(如使用 Kubernetes)
- 热门房间可独立扩容(房间维度的水平伸缩)
七、未来拓展方向
1. 连麦互动支持
- WebRTC + SFU 架构
- Java 控制信令服务(SDP 协议协商)
2. 云端录制 + 回放
- 推流同时录制 TS 文件
- Java 生成 m3u8 索引,支持时移播放
3. 弹幕系统
- Kafka + WebSocket 构建高并发弹幕管道
- Redis 做弹幕缓存、限速控制
八、总结
直播系统的推流和拉流是典型的高并发实时系统,对带宽、延迟、稳定性要求极高。Java 在控制面服务中依然扮演着关键角色,负责:
- 接入鉴权
- 房间管理
- 用户控制
- 拉流分发
- 数据上报与统计
而在流媒体处理方面,则需结合 C/C++、FFmpeg、Nginx-RTMP、Media Server 等高性能组件构建混合架构。