3系统设计面试:内幕指南(第2版)

设计YouTube

案例2

视频存储CDN视频转码

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第3章:设计YouTube(Design YouTube)

一、导读

1.1 本章学习目标

第3章以设计 YouTube 为案例,讲解如何处理海量视频数据的存储、转码和分发。核心挑战包括视频上传流程、视频转码、CDN 分发、自适应码率播放等。

本章的核心学习目标包括:

  • 理解视频上传的完整流程:分片上传 → 元数据存储 → 视频转码 → CDN 分发。
  • 掌握视频转码技术:H.264/H.265 编码、多分辨率输出、自适应码率(DASH/HLS)。
  • 学会存储设计:对象存储(S3/GCS)存储视频文件、元数据存关系型数据库。
  • 理解 CDN 分发机制:边缘缓存、预热策略、缓存失效。
  • 掌握视频播放优化:自适应码率切换、预加载、缓冲策略。
  • 学会数据规模估算:存储、带宽、QPS 的计算。

1.2 为什么本章如此重要

YouTube 是互联网上最大的视频平台之一,每天处理数亿小时的视频。设计一个类似系统需要解决存储、计算、网络三大领域的核心挑战。Alex Xu 通过这个案例展示了如何处理超大文件、高带宽、全球分发的系统设计。

1.3 核心问题引导

视频上传为什么要分片?如何处理上传中断?

视频转码为什么需要分布式处理?

CDN 如何减少视频播放延迟?

自适应码率(ABR)如何工作?

如何估算 YouTube 级别的存储和带宽需求?

视频推荐系统如何设计?


二、核心概念详解

2.1 需求分析与规模估算

// 功能需求:
// 1. 用户可以上传视频
// 2. 用户可以观看视频(播放、暂停、快进)
// 3. 视频支持多种分辨率
// 4. 根据网络状况自动切换分辨率
// 5. 视频搜索和推荐

// 非功能需求:
// 1. 高可用:99.99%
// 2. 低延迟:视频起播时间 < 2秒
// 3. 支持全球用户

// 规模估算:
// 每日上传视频:500万个
// 平均视频时长:5分钟 = 300秒
// 平均上传码率:4Mbps(720p)
// 平均视频大小:4Mbps × 300s / 8 = 150MB
// 每日上传数据量:500万 × 150MB = 750TB
// 每月上传数据量:750TB × 30 = 22.5PB
// 每年上传数据量:22.5PB × 12 = 270PB

// 转码后存储(多分辨率):
// 360p: 50MB, 480p: 80MB, 720p: 150MB, 1080p: 300MB, 4K: 1GB
// 每个视频转码5个版本:约1.58GB
// 每日转码存储:500万 × 1.58GB ≈ 7.9PB
// 每年转码存储:7.9PB × 365 ≈ 2.9EB(Exabyte)

// 带宽估算:
// DAU:10亿
// 平均每人每天观看30分钟
// 平均播放码率:2.5Mbps(720p)
// 每日播放数据量:10亿 × 30min × 60s × 2.5Mbps / 8 ≈ 562.5PB
// 平均带宽:562.5PB / 86400s ≈ 6.5Tbps

2.2 高层设计

// 系统架构:
//
// 上传流程:
// [Creator] → [Upload Service] → [Temp Storage (S3)]
//                                       ↓
//                                [Transcode Service]
//                                (分布式转码集群)
//                                       ↓
//                                [Video Storage (S3/GCS)]
//                                       ↓
//                                [CDN (边缘节点缓存)]
//
// 播放流程:
// [Viewer] → [API Server] → [Metadata DB]  → 获取视频信息
// [Viewer] → [CDN] → [Video Storage]       → 获取视频数据
//
// 核心组件:
// 1. Upload Service:处理视频上传(分片上传、断点续传)
// 2. Transcode Service:视频转码(多分辨率、多码率)
// 3. Video Storage:对象存储(S3/GCS)
// 4. Metadata DB:视频元数据(标题、描述、标签等)
// 5. CDN:全球分发视频内容
// 6. Recommendation Service:视频推荐

2.3 视频上传流程

2.3.1 分片上传

// 为什么需要分片上传?
// 1. 视频文件大(几百MB到几GB),单次上传容易失败
// 2. 分片上传支持断点续传
// 3. 可以并行上传多个分片,提高速度

// 分片上传流程:
// 1. 客户端请求上传 → 服务端返回 upload_id
// 2. 客户端将视频切分为 5MB 的分片
// 3. 客户端并行上传分片到对象存储(S3 Multipart Upload)
// 4. 所有分片上传完成 → 客户端通知服务端合并
// 5. 服务端验证分片完整性 → 标记上传完成

// 断点续传:
// 如果上传中断,客户端查询已上传的分片列表
// 只重新上传未完成的分片

2.3.2 上传状态机

// 视频状态流转:
// UPLOADING → UPLOADED → PROCESSING → READY → PUBLISHED
//                ↓           ↓
//             FAILED      FAILED
//
// UPLOADING:正在上传分片
// UPLOADED:所有分片上传完成
// PROCESSING:正在转码
// READY:转码完成,可以播放
// PUBLISHED:用户发布,对公众可见
// FAILED:上传或转码失败

2.4 视频转码

2.4.1 转码流程

// 转码是将原始视频转换为多种分辨率和码率的过程
//
// 原始视频 → 解码 → 缩放 → 编码 → 多分辨率输出
//
// 输出格式:
// 360p  (640×360)   → H.264, 500kbps
// 480p  (854×480)   → H.264, 1000kbps
// 720p  (1280×720)  → H.264, 2500kbps
// 1080p (1920×1080) → H.264, 5000kbps
// 4K    (3840×2160) → H.265, 15000kbps

// 转码为什么需要分布式处理?
// 1. 转码是 CPU 密集型操作
// 2. 每天500万个视频需要转码
// 3. 每个视频需要转码5个分辨率
// 4. 单个视频转码可能需要几分钟到几十分钟
//
// 分布式转码架构:
// [Upload Complete] → [Message Queue]
//                           ↓
//                    [Transcode Worker 1] → [S3: 360p]
//                    [Transcode Worker 2] → [S3: 480p]
//                    [Transcode Worker 3] → [S3: 720p]
//                    [Transcode Worker 4] → [S3: 1080p]
//                    [Transcode Worker 5] → [S3: 4K]
//                           ↓
//                    [All Complete] → 更新视频状态为 READY

2.4.2 自适应码率(ABR)

// 自适应码率允许播放器根据网络状况自动切换分辨率
//
// 两种主流协议:
// HLS(HTTP Live Streaming):Apple 开发,iOS/Safari 原生支持
// DASH(Dynamic Adaptive Streaming over HTTP):国际标准
//
// HLS 工作原理:
// 1. 视频被切分为 2-10 秒的片段(TS 文件)
// 2. 每个分辨率有独立的播放列表(M3U8 文件)
// 3. 主播放列表包含所有分辨率的入口
// 4. 播放器根据带宽自动选择最佳分辨率

// HLS 播放列表结构:
// 主播放列表(master.m3u8):
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360
360p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=854x480
480p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720
720p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5600000,RESOLUTION=1920x1080
1080p/playlist.m3u8

// 子播放列表(720p/playlist.m3u8):
#EXTM3U
#EXT-X-TARGETDURATION:6
#EXTINF:6.0,
segment_001.ts
#EXTINF:6.0,
segment_002.ts
#EXTINF:4.5,
segment_003.ts
#EXT-X-ENDLIST

// 播放器自适应逻辑:
// 1. 下载第一个片段(默认720p)
// 2. 测量下载耗时,估算带宽
// 3. 如果带宽充足 → 继续720p或升级到1080p
// 4. 如果带宽不足 → 降级到480p或360p
// 5. 每隔几个片段重新评估带宽

2.5 CDN 分发

// CDN(Content Delivery Network)将视频缓存到全球边缘节点
//
// 工作原理:
// 1. 用户请求视频 → DNS 解析到最近的边缘节点
// 2. 边缘节点有缓存 → 直接返回
// 3. 边缘节点无缓存 → 回源到 S3 获取 → 缓存到边缘 → 返回用户
//
// CDN 优化策略:
// 1. 预热(Pre-warming):
//    热门视频提前推送到边缘节点
//    避免首次访问的回源延迟
//
// 2. 缓存策略:
//    热门视频(Top 10%):缓存7天
//    普通视频:缓存1天
//    冷门视频:不缓存或缓存1小时
//
// 3. 分片缓存:
//    只缓存被请求的视频片段
//    未请求的片段不缓存
//
// CDN 提供商:
// YouTube 使用自建 CDN + Google Global Cache
// 其他选择:CloudFront、Akamai、Cloudflare

// 数据流:
// [Viewer] → [DNS] → [Nearest Edge Node]
//                         ↓ (cache hit)
//                      返回视频片段
//                         ↓ (cache miss)
//                      [Origin Server (S3)]
//                      获取 → 缓存 → 返回

2.6 数据库设计

sql
-- 视频元数据表
CREATE TABLE videos (
    video_id VARCHAR(36) PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    uploader_id BIGINT NOT NULL,
    duration_seconds INT,
    status ENUM('uploading', 'processing', 'ready', 'failed', 'published'),
    view_count BIGINT DEFAULT 0,
    like_count BIGINT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    published_at TIMESTAMP NULL,
    INDEX idx_uploader (uploader_id),
    INDEX idx_status (status),
    INDEX idx_created (created_at)
);

-- 视频文件表(每个分辨率一条记录)
CREATE TABLE video_files (
    file_id VARCHAR(36) PRIMARY KEY,
    video_id VARCHAR(36) NOT NULL,
    resolution ENUM('360p', '480p', '720p', '1080p', '4k'),
    codec VARCHAR(10) DEFAULT 'h264',
    file_size_bytes BIGINT,
    storage_url VARCHAR(512),
    cdn_url VARCHAR(512),
    duration_seconds INT,
    FOREIGN KEY (video_id) REFERENCES videos(video_id),
    INDEX idx_video (video_id)
);

-- 视频标签表
CREATE TABLE video_tags (
    video_id VARCHAR(36),
    tag VARCHAR(100),
    PRIMARY KEY (video_id, tag),
    INDEX idx_tag (tag)
);

三、实战案例

3.1 案例一:视频播放的完整流程

// 用户点击播放一个视频:
//
// 1. [Client] 请求视频信息
//    GET /api/videos/abc123
//    → [API Server] 查询 Metadata DB
//    → 返回视频信息(标题、时长、可用分辨率)
//
// 2. [Client] 请求主播放列表
//    GET https://cdn.youtube.com/videos/abc123/master.m3u8
//    → [CDN Edge] 返回 HLS 主播放列表
//
// 3. [Client] 选择初始分辨率(默认720p)
//    GET https://cdn.youtube.com/videos/abc123/720p/playlist.m3u8
//    → [CDN Edge] 返回片段列表
//
// 4. [Client] 下载第一个片段
//    GET https://cdn.youtube.com/videos/abc123/720p/segment_001.ts
//    → [CDN Edge] 返回视频数据
//
// 5. [Client] 播放第一个片段,同时预下载后续片段
//
// 6. [Client] 测量下载速度,决定是否切换分辨率
//    如果网速下降 → 切换到480p
//    GET https://cdn.youtube.com/videos/abc123/480p/segment_005.ts

3.2 案例二:存储成本估算

// YouTube 存储成本估算:
//
// 假设:
// 每日上传:500万视频
// 平均原始大小:150MB
// 转码后总大小:1.58GB(5个分辨率)
// 存储成本:$0.023/GB/月(S3 Standard)
//
// 每日新增存储成本:
// 原始:500万 × 150MB = 750TB → $17,250/天
// 转码:500万 × 1.58GB = 7.9PB → $181,700/天
// 总计:约 $199,000/天 = $600万/月
//
// CDN 带宽成本:
// 每日播放数据量:562.5PB
// CDN 成本:$0.02/GB(批量价格)
// 每日 CDN 成本:562.5PB × 1024 × $0.02 ≈ $11.5M/天
//
// 结论:YouTube 级别的基础设施成本极高
// 自建 CDN 比使用第三方 CDN 更经济

四、本章小结

核心知识点:

  • 视频上传采用分片上传 + 断点续传。
  • 视频转码使用分布式集群,输出多分辨率多码率。
  • HLS/DASH 实现自适应码率播放。
  • CDN 通过边缘缓存减少延迟,预热提升热门视频体验。
  • 对象存储(S3)存视频文件,关系型数据库存元数据。
  • YouTube 级别的基础设施成本极高,需要自建 CDN。

五、思考与练习

思考题

如何处理用户上传的违规视频?

直播和点播的架构有何本质区别?

视频去重如何设计?

练习题

设计视频上传的完整流程,包含分片上传和断点续传。

设计一个分布式转码系统的架构。

估算一个视频平台每月需要多少存储和带宽。

3/6设计Yo
0%