

模块 | 技术建议 |
|---|---|
视频上传 | Web/APP → 分片上传 → 后端合并 |
视频转码 | FFmpeg 异步转码,生成多码率 HLS/MP4 |
视频存储 | 对象存储 OSS/S3/MinIO |
视频分发 | CDN(阿里/腾讯/Cloudflare) |
后端 | PHP Laravel / Hyperf / Node.js / Java Spring Boot |
数据库 | MySQL(核心数据)、Redis(缓存、点赞计数、排行榜) |
消息队列 | RabbitMQ / Kafka(异步任务:转码、推送通知、统计) |
实时互动 | WebSocket / Socket.IO(点赞、评论通知) |
推荐算法 | Redis、ElasticSearch、Python/ML服务(协同过滤、推荐排序) |
日志与监控 | ELK / Prometheus + Grafana |
CDN防盗链 | URL签名 + Token鉴权 |
┌───────────────┐
│ 用户端 │
│ Web / iOS / Android │
└─────┬─────────┘
│ 上传视频/浏览/点赞/评论
▼
┌───────────────┐
│ 后端 API 服务 │
│ PHP Laravel │
│ MySQL / Redis │
└─────┬─────────┘
│ 异步任务
▼
┌───────────────┐
│ 任务队列 │
│ RabbitMQ/Kafka │
└─────┬─────────┘
│ 视频转码/生成缩略图/推送通知
▼
┌───────────────┐
│ 视频存储/OSS/S3│
└─────┬─────────┘
│ CDN分发
▼
┌───────────┐
│ 视频播放端 │
│ Web/APP │
└───────────┘
辅助服务:
- WebSocket/Socket.IO:实时点赞、评论、消息通知
- ML推荐服务:协同过滤、兴趣推荐
- 日志监控:Prometheus/Grafana/ELKCREATE 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 videos (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
title VARCHAR(255),
description TEXT,
video_url VARCHAR(512),
cover_url VARCHAR(512),
status TINYINT DEFAULT 0, -- 0:待审核 1:审核通过 2:拒绝
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE likes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
video_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE comments (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
video_id BIGINT,
content TEXT,
parent_id BIGINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE follows (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
follow_user_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE tags (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(64)
);
CREATE TABLE video_tags (
video_id BIGINT,
tag_id BIGINT
);阶段 | 核心功能 |
|---|---|
MVP(1-2 月) | 用户注册、视频上传、播放、点赞、评论 |
V1(2-3 月) | 视频转码、多码率播放、封面生成、审核、推荐首页 |
V2(2 月) | 搜索、话题标签、关注/粉丝、排行榜、通知 |
V3(2 月) | 视频编辑工具、滤镜贴纸、AI推荐、监控、风控 |
如果你需要,我可以帮你直接画出 短视频系统完整架构图 + 数据流示意 + PHP/Laravel 核心代码骨架,像我之前给你做赛事直播系统那样,直接可开发落地。
你希望我帮你画吗?
短视频系统源码,短视频平台开发,
太好了 — 我把 “短视频系统源码 + 平台开发可落地方案” 直接给你:架构、数据库、接口设计、关键源码片段(Laravel/PHP + 前端分片上传 + 转码 Worker + WebSocket 实时通知)、容器化部署示例(docker-compose)和开发 / 测试要点。你可以把这些文件直接落到代码仓库中开始开发。
我把内容分为:架构总览 → 数据库 → 接口 & 路由 → 前端上传(分片)→ 后端核心实现(Laravel 风格)→ 转码/Worker → 推荐/热度策略 → 存储/CDN & 防盗链 → 部署(docker-compose)→ 测试与上线要点。重点代码与命令都给出,可直接复制粘贴。
-- users
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(64) UNIQUE,
password_hash VARCHAR(255),
avatar VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- videos
CREATE TABLE videos (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
title VARCHAR(255),
description TEXT,
status TINYINT DEFAULT 0, -- 0:上传中 1:待审核 2:可播放 3:拒绝
original_url VARCHAR(512), -- 临时合并后的原始文件地址(本地或OSS)
hls_url VARCHAR(512), -- 生产环境播放地址(CDN)
mp4_url VARCHAR(512),
cover_url VARCHAR(512),
duration INT,
width INT, height INT,
views BIGINT DEFAULT 0,
likes BIGINT DEFAULT 0,
comments_count BIGINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX(user_id)
);
-- video_chunks (可选,用于记录分片)
CREATE TABLE video_chunks (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
upload_id VARCHAR(128),
chunk_index INT,
chunk_size INT,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- likes
CREATE TABLE likes (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
video_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY (user_id, video_id)
);
-- comments
CREATE TABLE comments (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT,
video_id BIGINT,
content TEXT,
parent_id BIGINT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);POST /api/v1/auth/login
POST /api/v1/videos/upload/init # 初始化上传 => 返回 upload_id
POST /api/v1/videos/upload/chunk # 上传分片 (upload_id, index)
POST /api/v1/videos/upload/complete # 合并分片 -> 触发转码任务
GET /api/v1/videos/{id} # 视频详情(含 hls_url)
GET /api/v1/feed # 推荐 / 关注 / 热门 列表
POST /api/v1/videos/{id}/like
POST /api/v1/videos/{id}/comment
WS /ws # WebSocket 连接 (token)分片上传适合大文件与不稳网络,示例使用 fetch 上传分片并在完成后通知后端合并。
// usage: await uploadFile(file)
async function uploadFile(file) {
// 1. init
const initResp = await fetch('/api/v1/videos/upload/init', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({filename: file.name, size: file.size})
});
const {upload_id, chunk_size} = await initResp.json();
// 2. slice & upload
const total = file.size;
let offset = 0, index = 0;
while (offset < total) {
const chunk = file.slice(offset, offset + chunk_size);
const form = new FormData();
form.append('upload_id', upload_id);
form.append('index', index);
form.append('chunk', chunk);
await fetch('/api/v1/videos/upload/chunk', { method: 'POST', body: form });
offset += chunk_size; index++;
}
// 3. complete
const completeResp = await fetch('/api/v1/videos/upload/complete', {
method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({upload_id})
});
const result = await completeResp.json();
return result; // 包含 video_id 等
}前端注意点:并行上传多个分片能提升速度,控制并发数(例如 3-5),并实现失败重试。
// VideoUploadController::init
public function init(Request $req) {
$user = $req->user();
$uploadId = bin2hex(random_bytes(16));
$chunkSize = 4 * 1024 * 1024; // 4MB
// 可把 uploadId 缓存在 Redis,记录 total_chunks / filesize 等
Cache::put("upload:{$uploadId}", ['user_id'=>$user->id,'filename'=>$req->filename,'size'=>$req->size], 3600);
return response()->json(['upload_id'=>$uploadId, 'chunk_size'=>$chunkSize]);
}// VideoUploadController::chunk
public function chunk(Request $req) {
$uploadId = $req->input('upload_id');
$index = $req->input('index');
$chunk = $req->file('chunk');
$tmpDir = storage_path("app/uploads/{$uploadId}");
if (!is_dir($tmpDir)) mkdir($tmpDir, 0755, true);
$chunk->move($tmpDir, sprintf('chunk_%05d', intval($index)));
// 可记录到 DB 或 Redis
return response()->json(['ok'=>true]);
}// VideoUploadController::complete
public function complete(Request $req) {
$uploadId = $req->input('upload_id');
$meta = Cache::get("upload:{$uploadId}");
if (!$meta) return response()->json(['error'=>'invalid'],400);
$tmpDir = storage_path("app/uploads/{$uploadId}");
$files = glob($tmpDir.'/chunk_*');
natsort($files);
$merged = storage_path("app/uploads/{$uploadId}.mp4");
$out = fopen($merged, 'ab');
foreach ($files as $f) {
$in = fopen($f, 'rb');
stream_copy_to_stream($in, $out);
fclose($in);
}
fclose($out);
// 可直接上传这份 merged 到 MinIO/OSS 并写 videos 表(status=0)
$video = \App\Models\Video::create([
'user_id'=>$meta['user_id'],
'title'=>'', 'description'=>'', 'status'=>0, 'original_url'=>$merged
]);
// 触发异步队列:转码、生成封面、推送到推荐索引
ProcessVideo::dispatch($video->id, $merged);
return response()->json(['video_id'=>$video->id]);
}使用 ffmpeg 在 Worker 容器中转码成多个分辨率、生成 HLS,上传到 OSS,并更新数据库。
// app/Jobs/ProcessVideo.php
class ProcessVideo implements ShouldQueue {
use Queueable;
protected $videoId; protected $localPath;
public function __construct($videoId, $localPath) {
$this->videoId = $videoId; $this->localPath = $localPath;
}
public function handle() {
$video = Video::find($this->videoId);
$id = $video->id;
$workDir = "/tmp/video_process/{$id}";
mkdir($workDir, 0755, true);
// 生成封面
$cover = "{$workDir}/cover.jpg";
$cmdCover = "ffmpeg -i {$this->localPath} -ss 00:00:01 -vframes 1 -q:v 2 {$cover}";
exec($cmdCover);
// 转码 - 生成 HLS 多码率
$hlsDir = "{$workDir}/hls";
mkdir($hlsDir,0755,true);
// 这里只给出简单命令,生产按需求做自适应码率 / 分辨率
$cmdHls = "ffmpeg -i {$this->localPath} -c:v libx264 -c:a aac -strict -2 -f hls -hls_time 6 -hls_list_size 0 {$hlsDir}/index.m3u8";
exec($cmdHls);
// 上传到对象存储(伪代码)
$hlsUrl = Storage::disk('oss')->putFileAs("videos/{$id}", new File("{$hlsDir}/index.m3u8"), "index.m3u8");
$coverUrl = Storage::disk('oss')->putFile("videos/{$id}", new File($cover));
$video->hls_url = $hlsUrl;
$video->cover_url = $coverUrl;
$video->status = 2; // 可播放
$video->save();
// 索引到搜索/推荐服务
dispatch(new IndexVideoToSearch($video->id));
}
}生产注意:ffmpeg 参数须根据场景做复杂配置(多路转码/自适应/分段策略/加密切片等),可用 supervisord 管理 worker 进程。
示例消息模型(JSON):
{ "type":"like", "video_id":123, "user_id":456, "ts":1630000000 }GET /api/v1/feed?type=for_you 返回已排序的视频列表(包含 hls_url、cover、reason)
简单排序公式示例(伪):
score = alpha * recency_score + beta * user_match_score + gamma * popularity_score示例:签名 URL(伪)
function signedUrl($path, $secret, $expire=300) {
$ts = time() + $expire;
$sig = hash_hmac('sha256', $path . '|' . $ts, $secret);
return $path . '?ts=' . $ts . '&sig=' . $sig;
}下面给出简化版 docker-compose,用于本地开发(PHP + MySQL + Redis + MinIO + Worker)。SRS / CDN /生产 ffmpeg worker 应另行部署。
version: '3.7'
services:
php:
image: ghcr.io/your/php-laravel:8.1
build: ./php
ports: ['8000:80']
volumes: ['./api:/var/www/html']
depends_on: ['mysql','redis','minio']
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD:root
MYSQL_DATABASE=video
ports: ['3306:3306']
volumes: ['./data/mysql:/var/lib/mysql']
redis:
image: redis:6
ports: ['6379:6379']
minio:
image: minio/minio
command: server /data
environment:
MINIO_ROOT_USER: minio
MINIO_ROOT_PASSWORD: minio123
ports: ['9000:9000']
volumes: ['./data/minio:/data']
worker:
image: your/worker-image
build: ./worker
depends_on: ['php','minio']说明:生产环境需要分离 ffmpeg 转码节点(带GPU/更大CPU)和流媒体(如果做直播)。本 compose 仅做快速迭代开发。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。