設計影音串流服務

問題定義

ℹ️面試經典題

「設計一個類似 YouTube / Netflix 的影音串流服務」是系統設計面試的高頻題目。重點不在功能完整,而在展示你對大規模非同步處理CDN 架構串流協議的理解。

設計一個影音平台,支援創作者上傳影片,觀眾在各種裝置上流暢觀看。

需求分析

Functional Requirements

Non-Functional Requirements

注意事項

⚠️影片轉碼是最昂貴的環節

一支 1 小時 4K 影片的轉碼可能需要數十分鐘 CPU 運算。絕對不能同步處理——必須用非同步任務佇列,並且支援水平擴展 Worker。轉碼失敗要能自動重試,部分失敗(例如 720p 成功但 480p 失敗)要能單獨重跑。

設計流程

1

大檔案分塊上傳

Client 將影片切成 5MB 區塊,支援斷點續傳,上傳到 Object Storage

2

觸發轉碼流水線

上傳完成後發送訊息到 Task Queue,啟動 DAG 轉碼排程

3

平行轉碼

多個 Worker 同時處理不同解析度,產出 HLS/DASH 分段檔案

4

分發到 CDN

轉碼完成的分段檔案推送到全球 CDN 節點,就近服務觀眾

5

Adaptive Bitrate 播放

播放器根據網速動態切換解析度分段,維持流暢體驗

架構設計

上傳流程

Client 將大檔案切成固定大小的 chunk,透過 Presigned URL 直接上傳到 Object Storage(S3),避免 API Server 成為瓶頸。上傳完成後,API Server 在 Metadata DB 記錄影片資訊,並發送轉碼任務到 Message Queue。

轉碼流水線(DAG Pipeline)

轉碼不是單一步驟,而是一個有向無環圖(DAG,Directed Acyclic Graph),即一組有依賴關係但無循環的任務。各步驟的依賴關係如下:

  1. 提取音訊 → 獨立處理音訊編碼(AAC 格式,128kbps-320kbps)。與視訊轉碼平行執行,互不依賴
  2. 產生縮圖 → 從關鍵幀(I-Frame)每隔 10 秒擷取一張預覽圖,用於播放器的進度條預覽。與視訊轉碼平行執行
  3. 多解析度轉碼 → 1080p / 720p / 480p / 360p 四個任務平行處理。每個解析度獨立轉碼,使用 H.264(相容性最好)或 H.265/HEVC(壓縮率高 40% 但編碼慢 2-3 倍)
  4. 產生 Manifest → 等所有解析度轉碼完成後才執行。組合所有分段檔案的 HLS .m3u8 或 DASH .mpd 播放清單

轉碼的具體技術細節

轉碼成本與優化策略

程式碼範例:轉碼任務排程

C# 版本

csharp
public record TranscodeJob(string VideoId, string SourceUrl, Resolution Target);
 
public enum Resolution { R360p, R480p, R720p, R1080p }
 
public class TranscodeOrchestrator
{
    private readonly IMessageQueue _queue;
 
    public TranscodeOrchestrator(IMessageQueue queue) => _queue = queue;
 
    public async Task ScheduleTranscoding(string videoId, string sourceUrl)
    {
        var resolutions = new[] { Resolution.R360p, Resolution.R480p,
                                  Resolution.R720p, Resolution.R1080p };
 
        var jobs = resolutions.Select(r =>
            new TranscodeJob(videoId, sourceUrl, r));
 
        foreach (var job in jobs)
        {
            await _queue.Enqueue("transcode", job);
        }
    }
}

TypeScript 版本

typescript
type Resolution = "360p" | "480p" | "720p" | "1080p";
 
interface TranscodeJob {
  videoId: string;
  sourceUrl: string;
  target: Resolution;
}
 
class TranscodeOrchestrator {
  constructor(private queue: MessageQueue) {}
 
  async scheduleTranscoding(videoId: string, sourceUrl: string): Promise<void> {
    const resolutions: Resolution[] = ["360p", "480p", "720p", "1080p"];
 
    const jobs: TranscodeJob[] = resolutions.map((target) => ({
      videoId,
      sourceUrl,
      target,
    }));
 
    await Promise.all(jobs.map((job) => this.queue.enqueue("transcode", job)));
  }
}

Python 版本

python
from dataclasses import dataclass
from enum import Enum
 
class Resolution(Enum):
    R360P = "360p"
    R480P = "480p"
    R720P = "720p"
    R1080P = "1080p"
 
@dataclass
class TranscodeJob:
    video_id: str
    source_url: str
    target: Resolution
 
class TranscodeOrchestrator:
    def __init__(self, queue):
        self._queue = queue
 
    async def schedule_transcoding(self, video_id: str, source_url: str):
        for resolution in Resolution:
            job = TranscodeJob(video_id, source_url, resolution)
            await self._queue.enqueue("transcode", job)

Adaptive Bitrate Streaming(ABR)詳解

ABR 是讓影片在各種網路環境下都能流暢播放的核心技術。它的完整運作流程:

  1. 初始化:播放器下載 Manifest 檔(HLS 的 .m3u8 或 DASH 的 .mpd),取得所有可用解析度和對應的分段 URL 列表
  2. 首段選擇:播放器從最低解析度(如 360p)開始播放,確保最快啟動。或者根據用戶的歷史網速記錄選擇合適的初始解析度
  3. 頻寬估測:每下載完一個分段,播放器計算實際下載速率(分段大小 / 下載時間)
  4. 解析度切換決策:如果連續 3 個分段的下載速率都高於目標解析度的 Bitrate,則升檔(如 480p → 720p)。如果緩衝區剩餘時間低於 5 秒,則降檔。這個演算法稱為 ABR Algorithm,常見的有 Buffer-Based(BBA)和 Throughput-Based 兩類
  5. 無縫切換:因為每個分段都是獨立的,播放器可以在任意分段邊界切換解析度,用戶感知上是流暢的

各解析度的 Bitrate 參考值

| 解析度 | 影片 Bitrate | 音訊 Bitrate | 每小時檔案大小 | |--------|-------------|-------------|--------------| | 360p | 0.5-1 Mbps | 64 kbps | 約 250 MB | | 480p | 1-2 Mbps | 128 kbps | 約 500 MB | | 720p | 2-4 Mbps | 128 kbps | 約 1 GB | | 1080p | 4-8 Mbps | 256 kbps | 約 2 GB | | 4K | 15-25 Mbps | 320 kbps | 約 7 GB |

HLS vs DASH 對比

架構圖

Client (Upload)
chunked upload
API Server
save info
Object Storage (S3)
distribute
Message Queue
dispatch
Transcode Workers
save segments
Metadata DB
CDN
ABR Player

上圖展示了影音串流的兩條路徑。上傳路徑(左→右):Client 將影片分塊上傳到 S3,API Server 記錄 Metadata 並將轉碼任務推入 Queue,Worker 轉碼完成後將分段檔案存回 S3 並分發到 CDN。播放路徑(右→左):ABR Player 從 API Server 取得 Manifest,再從最近的 CDN 節點逐段下載影片分段,根據網速動態切換解析度。

延伸討論

💡資深開發者筆記

DRM(數位版權管理):付費內容必須加密。三大 DRM 系統:

  • Widevine(Google):覆蓋 Android、Chrome、大部分智慧電視
  • FairPlay(Apple):覆蓋 iOS、macOS、Safari
  • PlayReady(Microsoft):覆蓋 Windows、Edge、Xbox 加密在轉碼後、分發前進行。每個分段檔案用 AES-128 加密,播放器需要先向 License Server 取得解密金鑰才能播放。

推薦系統:影片的觀看完成率、點擊率是核心特徵。協同過濾(Collaborative Filtering,「看過 A 的人也看了 B」)結合內容特徵(標籤、分類)是業界常見做法。推薦系統通常獨立為一個微服務,與串流服務解耦。

CDN 成本控制:CDN 流量是影音平台最大的營運成本(Netflix 每月 CDN 費用估計數千萬美元)。優化策略包括:

  • 自建 CDN 節點:Netflix 的 Open Connect 在全球 ISP 機房部署自有伺服器,減少對第三方 CDN 的依賴
  • 冷熱分層:熱門影片(前 20%)推送到所有 CDN 節點,冷門影片只保留在 Origin Storage,首次請求時才拉取到邊緣節點
  • 預載策略:根據用戶的觀看歷史和推薦結果,在用戶可能觀看前就將影片預載到最近的 CDN 節點

面試常見問題與參考答案

Q1:如何支援直播串流(Live Streaming)?與點播(VOD)有何不同?

A1:直播與點播的核心差異在於「內容是否已經存在」:

Q2:如何確保上傳的大檔案不遺失?

A2:三道防線確保持久性:

  1. 分塊上傳 + 校驗:每個 Chunk 上傳後,Server 回傳該 Chunk 的 MD5/SHA-256,Client 比對確認無損
  2. S3 持久性:AWS S3 Standard 的持久性為 99.999999999%(11 個 9),自動在 3 個以上的 Availability Zone 儲存副本
  3. 上傳狀態追蹤:Metadata DB 記錄每個 Chunk 的上傳狀態。如果上傳中斷,Client 重新連線後查詢已完成的 Chunk,只續傳缺少的部分

Q3:Presigned URL 是什麼?為什麼上傳不經過 API Server?

A3:Presigned URL 是一個帶有簽名的臨時 URL,允許 Client 直接對 S3 進行上傳/下載,無需經過 API Server。流程:

  1. Client 向 API Server 請求上傳權限
  2. API Server 驗證身份後,用 AWS SDK 產生 Presigned URL(包含操作類型、過期時間、簽名)
  3. Client 直接用這個 URL 上傳到 S3,不經過 API Server 好處是避免 API Server 成為頻寬瓶頸——一支 5 GB 的影片如果經過 API Server 中轉,會佔用大量網路頻寬和連線數。Presigned URL 讓上傳流量直接走 S3,API Server 只處理輕量的 Metadata 請求。

理解測驗

🤔 為什麼影片上傳要用分塊(Chunked Upload)而不是一次傳完?

🤔 Adaptive Bitrate Streaming 的核心機制是什麼?

🤔 為什麼轉碼任務必須非同步處理?

重點整理

💡一句話記住

影音串流 = 大檔案分塊上傳 + 非同步 DAG 轉碼 + CDN 就近分發 + ABR 自適應播放。

記憶口訣:「分塊傳,平行碼,CDN 散,ABR 換」(分塊上傳、平行轉碼、CDN 分散、ABR 切換畫質)。

| 概念 | 說明 | |------|------| | Chunked Upload | 大檔案切成 5MB 區塊,透過 Presigned URL 直接傳到 S3,支援斷點續傳 | | Transcode Pipeline | DAG 排程:音訊提取、縮圖產生、多解析度轉碼平行執行,最後產生 Manifest | | Codec | H.264(最通用)、H.265(壓縮率高 40% 但慢 2-3 倍)、AV1(免費但慢 5-10 倍) | | HLS / DASH | HLS 用 .m3u8 + .ts(Apple 生態),DASH 用 .mpd + .m4s(開放標準),分段 6 秒 | | CDN | 熱門影片推送全球節點,冷門影片首次請求才拉取。自建 CDN(如 Netflix Open Connect)降本 | | Adaptive Bitrate | 播放器監測下載速率,連續 3 段高於目標 Bitrate 則升檔,緩衝區低於 5 秒則降檔 | | DRM | Widevine(Google)+ FairPlay(Apple)+ PlayReady(Microsoft)覆蓋所有裝置 | | 成本優化 | Spot Instance 省 60-90% 轉碼費、冷門影片按需轉碼、CDN 冷熱分層 |

你可能也想看

設計搜尋自動補全設計分散式檔案儲存

按 ← → 鍵切換課程