1 系统目标 核心目标:为体育赛事、电竞赛事或大型活动提供实时直播平台,支持观众观看、互动、统计、回放及多分辨率直播。
核心特点:
高并发:成千上万观众同时在线
稳定低延迟:赛事直播对延迟要求高
多终端支持:Web、iOS、Android、电视端
数据统计与分析:观众数、活跃度、弹幕、礼物/打赏
2 技术选型模块
技术建议
流媒体服务器
SRS、ZLMediaKit、nginx-rtmp(测试用)
推流协议
RTMP(主播)、WebRTC(低延迟)、SRT(远程赛事)
播放协议
HLS(兼容)、HTTP-FLV(低延迟)、WebRTC(实时)
后端
PHP(Laravel/Hyperf)、Node.js(可选)、Java(可选)
实时通信
Swoole WebSocket、Socket.IO、IM SDK(腾讯云/环信)
数据库
MySQL(核心业务)、Redis(在线状态/缓存/计数)
对象存储
OSS/S3/MinIO(回放、录制)
CDN
阿里/腾讯/Cloudflare 分发 HLS/FLV
异步任务
RabbitMQ/Kafka(转码、统计、消息队列)
监控
Prometheus + Grafana
日志
ELK / Loki
3 架构设计代码语言:javascript复制Clients
├─ 主播/裁判推流 (OBS/APP/SRT) --> RTMP/SRT --> 流媒体集群 (SRS/ZL)
├─ 观众 Web / Mobile --> HLS/HTTP-FLV/WebRTC --> CDN
└─ Chat / 弹幕客户端 --> WebSocket / IM 服务
Backend Services
├─ API 服务 (PHP/Node) --> MySQL + Redis
├─ 流媒体回调处理 (on_publish/on_close)
├─ 异步任务 (转码/录制/统计)
├─ 礼物/打赏服务
├─ 赛事管理/排期/房间管理
└─ 监控/运维/报警
Storage & Infra
├─ MySQL/Redis
├─ OSS/S3/MinIO (录制回放)
├─ CDN 分发
├─ Prometheus/Grafana 监控
└─ 日志 ELK / Loki4 核心功能模块 用户与权限管理
主播、裁判、管理员、观众角色
房间/赛事权限控制
赛事管理模块
赛事创建、排期
多场次直播管理
主播绑定赛事、裁判操作管理
直播模块
RTMP 推流 → 流媒体服务器 → CDN/HLS/FLV
推流鉴权(stream_key + on_publish 校验)
播放端鉴权(短期签名 token、防盗链)
互动模块
弹幕、聊天室、投票、竞猜
礼物/打赏系统(可选)
录制与回放
流媒体录制 → 分段 TS → 转 MP4 → 上传 OSS/S3
回放管理(按赛事/房间/时间)
支持延迟回放、精确片段回放
统计与分析
观众数、活跃度、峰值并发
弹幕量、礼物量
赛事数据分析(热门时段、留存率)
安全与风控
推流/播放鉴权
防刷礼物、防刷弹幕
版权保护策略(水印、token、CDN 防盗链)
5 数据库设计示例代码语言:javascript复制CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64),
password_hash VARCHAR(255),
role TINYINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
start_time DATETIME,
end_time DATETIME,
status TINYINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE rooms (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
event_id BIGINT,
owner_id BIGINT,
stream_key VARCHAR(128),
is_live TINYINT DEFAULT 0,
viewers_count INT DEFAULT 0,
hls_url VARCHAR(512),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE streams (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
room_id BIGINT,
start_at DATETIME,
stop_at DATETIME,
record_url VARCHAR(512)
);
CREATE TABLE messages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
room_id BIGINT,
user_id BIGINT,
type VARCHAR(32),
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);6 推流 & 播放流程 主播推流
OBS/SRT → RTMP/SRT → 流媒体
流媒体 on_publish 回调到 PHP 后端 → 验证 stream_key → 允许推流
观众播放
前端请求 play_token → 后端生成 HMAC 短期 token
播放器拉取 HLS/FLV → 流媒体/NGINX 验签
WebSocket 弹幕实时更新
结束直播
流媒体 on_close 回调 → 后端标记 stop_at → 触发录制转码任务
回放生成,存储到对象存储
7 弹幕与实时互动设计 架构:WebSocket + Redis Pub/Sub
消息处理:
写 Redis 队列 → 多 worker 异步落库
广播到房间的所有观众
限流与防刷:
每 IP/UID 每秒消息限制
关键事件(打赏/竞猜)事务处理
8 录制与回放策略 流媒体直接录制 TS 分片(建议 5-10 分钟)
异步转码 MP4 → 上传 OSS/S3
回放管理:
按赛事/房间/主播分类
支持片段播放或整场回放
支持 HLS 流回放
9 部署与运维建议 分层部署:
流媒体集群独立,高带宽节点
API、WebSocket 服务独立,可容器化
CDN 分发:
HLS/FLV 走 CDN,origin 仅处理少量请求
监控:
在线人数、推流/拉流状态、CPU、带宽、延迟
Prometheus + Grafana + ELK/Loki
安全:
推流/播放鉴权 + 防盗链
弹幕/打赏防刷
10 开发与迭代建议阶段
核心目标
MVP(1-2 月)
房间管理、推流鉴权、HLS/FLV 播放、基础弹幕
V1(2-3 月)
录制/回放、赛事管理、礼物/打赏、WebSocket 弹幕
V2(2 月)
多机房部署、CDN 集成、低延迟 WebRTC、统计分析
V3(2 月)
风控、版权保护、私有化部署、监控告警、可扩展架构
11 注意事项 流媒体与业务分离,带宽压力由流媒体/CDN承担
弹幕、礼物、订单异步化,避免主流程阻塞
安全鉴权设计必须从 MVP 阶段就落地
高并发场景下 Redis、WebSocket、数据库主从读写分离必须规划好
架构图(文本版示意)代码语言:javascript复制 ┌─────────────┐
│ 主播/裁判端 │
│ OBS / APP │
└─────┬───────┘
│ RTMP/SRT/WebRTC
▼
┌───────────────┐
│ 流媒体服务器 │
│ SRS/ZLMediaKit│
└─────┬─────────┘
│ HLS/FLV/WebRTC
▼
CDN分发
│
┌────────────┴─────────────┐
│ 观众端 │
│ Web/APP/TV │
│ 播放 HLS/FLV/WebRTC │
│ 弹幕 WebSocket/IM │
└────────────┬─────────────┘
│
▼
┌───────────────┐
│ 业务后端 API │
│ PHP Laravel │
│ MySQL/Redis │
│ WebSocket/Swoole
└─────┬─────────┘
│
┌───────────┴────────────┐
│ 异步任务/转码/录制 Worker│
│ RabbitMQ/Kafka + FFmpeg │
└───────────┬────────────┘
│
┌───────┴────────┐
│ 对象存储/OSS/S3 │
│ 录制回放文件 │
└────────────────┘2️⃣ 核心数据流推流流程
主播获取 stream_key → OBS / APP 推 RTMP/SRT
流媒体触发 on_publish 回调 → PHP API 验证 stream_key
后端更新 rooms.is_live=1,触发 WebSocket 通知观众
前端观众请求 play_token → 拉 HLS/FLV/WebRTC 流
断流/回放流程
流媒体触发 on_close 回调
后端标记 streams.stop_at
异步任务 worker 处理录制文件 → 转码 MP4 → 上传 OSS/S3
回放 URL 写回数据库,前端可按赛事或房间查询回放
弹幕/互动
WebSocket 客户端连接带 token
消息先写 Redis 队列 → worker 异步落库
广播到房间所有观众
3️⃣ PHP/Laravel 核心代码骨架示例3.1 数据库模型代码语言:javascript复制// app/Models/User.php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable {
protected $fillable = ['username','password','role'];
}
// app/Models/Event.php
class Event extends Model {
protected $fillable = ['name','start_time','end_time','status'];
}
// app/Models/Room.php
class Room extends Model {
protected $fillable = ['event_id','owner_id','stream_key','is_live','viewers_count','hls_url'];
}
// app/Models/Stream.php
class Stream extends Model {
protected $fillable = ['room_id','start_at','stop_at','record_url'];
}3.2 流媒体回调 Controller代码语言:javascript复制// app/Http/Controllers/StreamHookController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Room;
use App\Models\Stream;
class StreamHookController extends Controller {
// 推流开始
public function onPublish(Request $request){
$streamKey = $request->input('name');
$room = Room::where('stream_key', $streamKey)->first();
if(!$room) return response('Unauthorized', 401);
$room->is_live = 1;
$room->save();
// 新增 stream 记录
Stream::create([
'room_id' => $room->id,
'start_at' => now()
]);
return response('OK', 200);
}
// 推流结束
public function onClose(Request $request){
$streamKey = $request->input('name');
$room = Room::where('stream_key', $streamKey)->first();
if(!$room) return response('Unauthorized', 401);
$room->is_live = 0;
$room->save();
$stream = Stream::where('room_id',$room->id)->latest()->first();
$stream->stop_at = now();
$stream->save();
// 触发异步任务: 转码/上传 OSS
dispatch(new \App\Jobs\ProcessStream($stream));
return response('OK', 200);
}
}3.3 播放 token 生成示例代码语言:javascript复制// app/Http/Controllers/PlayTokenController.php
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Cache;
class PlayTokenController extends Controller {
public function getToken(Request $request, $roomId){
$room = Room::findOrFail($roomId);
$token = hash_hmac('sha256', $room->stream_key.'|'.time(), env('APP_KEY'));
// 缓存 token 5分钟
Cache::put('play_token_'.$token, $room->id, 300);
return response()->json(['token'=>$token, 'hls_url'=>$room->hls_url]);
}
}3.4 路由示例代码语言:javascript复制// routes/api.php
use App\Http\Controllers\StreamHookController;
use App\Http\Controllers\PlayTokenController;
Route::post('/hook/on_publish', [StreamHookController::class,'onPublish']);
Route::post('/hook/on_close', [StreamHookController::class,'onClose']);
Route::get('/rooms/{id}/play-token', [PlayTokenController::class,'getToken']);3.5 异步录制/转码 Worker 示例代码语言:javascript复制// app/Jobs/ProcessStream.php
namespace App\Jobs;
use App\Models\Stream;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
class ProcessStream implements ShouldQueue {
use Queueable;
protected $stream;
public function __construct(Stream $stream){ $this->stream = $stream; }
public function handle(){
$file = "/recordings/{$this->stream->id}.ts";
$output = "/recordings/{$this->stream->id}.mp4";
exec("ffmpeg -i $file -c:v copy -c:a copy $output");
// 上传 OSS/S3 (示例)
// Storage::disk('oss')->putFileAs('streams',$output,"{$this->stream->id}.mp4");
$this->stream->record_url = "/oss/streams/{$this->stream->id}.mp4";
$this->stream->save();
}
}✅ 这样一套架构 + 数据流 + 核心 PHP 代码骨架,已经可以直接作为赛事直播系统开发模板,包括推流/断流、play token、防盗链、录制回放、异步转码。
