設計一個類似 YouTube 的影片分享服務,使用者可以上傳、觀看、搜尋影片。

  • 類似服務:Netflix、Vimeo、Dailymotion
  • 難度:中等

為什麼選擇 YouTube#

YouTube 是全球最受歡迎的影片分享平台之一。使用者可以在平台上上傳、觀看、分享、評分、檢舉影片,以及對影片留言。

系統需求與目標#

功能性需求#

  1. 使用者可以上傳影片
  2. 使用者可以分享與觀看影片
  3. 使用者可以根據影片標題進行搜尋
  4. 系統需要記錄影片統計數據(如按讚數、不喜歡數、總觀看次數等)
  5. 使用者可以對影片新增與查看留言

非功能性需求#

  1. 高可靠性(Reliability):任何上傳的影片都不應遺失
  2. 高可用性(Availability):一致性可以稍微犧牲;使用者短暫看不到新影片是可以接受的
  3. 即時體驗:使用者觀看影片時應該感受不到延遲

本設計不涵蓋影片推薦、熱門影片、頻道訂閱、稍後觀看、收藏等功能。

容量估算與限制#

流量估算#

  • 總使用者:15 億
  • 每日活躍使用者(DAU):8 億
  • 平均每位使用者每天觀看 5 部影片
  • 每秒影片觀看數:800M * 5 / 86400 ≈ 46K videos/sec
  • 上傳與觀看比例為 1:200
  • 每秒影片上傳數:46K / 200 ≈ 230 videos/sec

儲存估算#

  • 每分鐘有 500 小時的影片被上傳
  • 平均每分鐘影片需要 50MB 儲存空間(需儲存多種格式)
  • 每分鐘儲存需求:500 hours * 60 min * 50MB ≈ 1500 GB/min(25 GB/sec)

以上數據為估算值,未考慮影片壓縮與副本,實際數據會有所不同。

頻寬估算#

  • 上傳頻寬:500 hours * 60 min * 10MB ≈ 300 GB/min(5 GB/sec)
  • 以 1:200 的上傳觀看比計算,需要約 1 TB/s 的輸出頻寬

系統 API#

可使用 SOAP 或 REST API 來提供服務功能。

上傳影片 API#

uploadVideo(api_dev_key, video_title, video_description, tags[],
            category_id, default_language, recording_details, video_contents)

參數說明

  • api_dev_key(string):已註冊帳號的 API 開發者金鑰,可用於流量限制(throttle)
  • video_title(string):影片標題
  • video_description(string):影片描述(可選)
  • tags(string[]):影片標籤(可選)
  • category_id(string):影片類別,如電影、歌曲、人物等
  • default_language(string):影片語言,如英文、中文、印地文等
  • recording_details(string):影片拍攝地點
  • video_contents(stream):影片內容

回傳值

  • 上傳成功回傳 HTTP 202(Request Accepted)
  • 影片編碼完成後,透過電子郵件通知使用者,並附上影片連結
  • 可提供查詢 API 讓使用者了解上傳影片的當前處理狀態

搜尋影片 API#

searchVideo(api_dev_key, search_query, user_location,
            maximum_videos_to_return, page_token)

參數說明

  • api_dev_key(string):已註冊帳號的 API 開發者金鑰
  • search_query(string):搜尋字串
  • user_location(string):使用者地理位置(可選)
  • maximum_videos_to_return(number):單次請求回傳的最大結果數
  • page_token(string):指定回傳結果集中的頁面

回傳值

  • JSON 格式,包含符合搜尋條件的影片資源清單
  • 每筆影片資源包含:影片標題、縮圖、建立日期、觀看次數

高層級設計#

系統在高層級需要以下元件:

  1. Processing Queue(處理佇列):每部上傳的影片會推入處理佇列,之後出列進行編碼、縮圖生成與儲存
  2. Encoder(編碼器):將上傳的影片編碼為多種格式
  3. Thumbnails Generator(縮圖產生器):為每部影片生成多張縮圖
  4. Video and Thumbnail Storage(影片與縮圖儲存):使用分散式檔案儲存系統儲存影片與縮圖檔案
  5. User Database(使用者資料庫):儲存使用者資訊(姓名、電子郵件、地址等)
  6. Video Metadata Storage(影片中繼資料儲存):儲存影片相關資訊(標題、檔案路徑、上傳者、觀看次數、按讚數等),也用於儲存影片留言

圖 18.1:高層級架構圖(Client → Web Server → App Server → Processing Queue → Encode / User DB / Metadata DB / Video Storage)

資料庫設計#

Video Metadata Storage(MySQL)#

影片中繼資料可儲存於 SQL 資料庫,每部影片需儲存以下資訊:

  • VideoID
  • Title
  • Description
  • Size
  • Thumbnail
  • Uploader / User
  • Total number of likes
  • Total number of dislikes
  • Total number of views

每則影片留言需儲存:

  • CommentID
  • VideoID
  • UserID
  • Comment
  • TimeOfCreation

User Data Storage(MySQL)#

  • UserID、Name、Email、Address、Age、Registration details 等

詳細元件設計#

本服務為讀取密集型,讀寫比例約為 200:1(每次上傳對應 200 次觀看),因此重點在於建立能快速擷取影片的系統。

影片儲存位置#

影片可儲存於分散式檔案儲存系統,如 HDFS 或 GlusterFS。

讀取流量管理#

  • 讀取流量與寫入流量分離
  • 由於每部影片有多份副本,可將讀取流量分散至不同伺服器
  • 中繼資料採用 Master-Slave 架構:寫入先到 Master,再同步到所有 Slave
  • 此架構可能造成短暫的資料過期(staleness),但在本系統中可以接受,因為延遲僅為毫秒等級

縮圖儲存#

縮圖數量遠多於影片(假設每部影片有 5 張縮圖),需考慮兩點:

  1. 縮圖為小檔案,最大約 5KB
  2. 縮圖的讀取流量遠大於影片(使用者一次觀看一部影片,但可能同時瀏覽 20 張縮圖)

Bigtable 是合理的選擇,因為它能將多個小檔案合併為一個 block 儲存於磁碟,並且高效讀取少量資料。將熱門縮圖放入快取可進一步降低延遲,由於縮圖檔案小,可以輕鬆在記憶體中快取大量檔案。

影片上傳#

由於影片檔案可能很大,若上傳中途連線中斷,系統應支援斷點續傳(resume)

影片編碼#

新上傳的影片儲存至伺服器後,會在處理佇列中新增一個任務來將影片編碼為多種格式。所有編碼完成後,通知上傳者,影片即可供觀看與分享。

圖 18.2:詳細系統架構圖(含 CDN、Video & Image Cache、Thumbnails Storage 等)

Metadata Sharding#

由於每天有大量新影片且讀取負載極高,需要將資料分散到多台機器上。以下為不同的分片策略:

基於 UserID 的分片#

  • 將某位使用者的所有資料儲存在同一台伺服器上
  • 透過 Hash Function 將 UserID 對應到特定資料庫伺服器
  • 搜尋影片標題時,需要查詢所有伺服器,再由中央伺服器彙總與排名結果

問題

  1. 熱門使用者:該使用者所在的伺服器可能成為效能瓶頸
  2. 資料分佈不均:部分使用者可能上傳大量影片,難以維持均勻分佈

可使用重新分區(repartition)Consistent Hashing 來平衡伺服器間的負載。

基於 VideoID 的分片#

  • Hash Function 將每個 VideoID 對應到隨機伺服器
  • 查找使用者影片時仍需查詢所有伺服器並彙總排名
  • 解決了熱門使用者的問題,但熱門影片仍可能造成負載不均
  • 可在資料庫伺服器前加入快取(Cache) 儲存熱門影片來進一步提升效能

影片去重(Video Deduplication)#

大量使用者上傳海量影片資料,服務必須處理影片重複問題。重複影片可能在長寬比、編碼格式、浮水印或邊框上有所不同,也可能是較長影片的片段。

重複影片的影響#

  1. 儲存空間:浪費空間儲存同一影片的多份副本
  2. 快取效率:重複影片佔用快取空間,降低快取效率
  3. 網路使用:增加網路傳輸量
  4. 能源消耗:以上低效率導致能源浪費

對使用者而言,會造成重複搜尋結果、較長的影片啟動時間、串流中斷等問題。

去重策略#

  • 在使用者上傳時進行去重(Inline Deduplication),而非事後處理,可節省大量編碼、傳輸與儲存資源
  • 使用者開始上傳時,服務執行影片比對演算法(如 Block Matching、Phase Correlation 等)來偵測重複
  • 若已存在相同影片的副本,可以停止上傳並使用現有副本,或若新上傳品質較高則採用新版本
  • 若新影片是現有影片的子片段(或反之),可智慧地將影片分割為較小的區塊,僅上傳缺少的部分

負載平衡(Load Balancing)#

  • 在快取伺服器間使用 Consistent Hashing 來平衡負載
  • 使用靜態 Hash 方案將影片對應到主機名稱,可能因影片熱門程度不同導致負載不均
  • 繁忙的伺服器可將客戶端重導向到同一快取位置中較空閒的伺服器
  • 可使用 Dynamic HTTP Redirections 實現

重導向的缺點:

  • 本地負載平衡可能導致多次重導向
  • 每次重導向需要額外的 HTTP 請求,增加影片開始播放前的延遲
  • 跨層級(Cross Data-Center)重導向可能將客戶端導向較遠的快取位置

快取(Cache)#

影片內容快取#

  • 使用大量地理分佈式影片快取伺服器將內容推送到靠近使用者的位置
  • 需要制定策略以最大化使用者效能均勻分佈快取伺服器負載

Metadata 快取#

  • 為 Metadata 伺服器引入快取,用於快取熱門資料庫行
  • 使用 Memcache 快取資料,Application Server 在存取資料庫前先檢查快取
  • 使用 LRU(Least Recently Used) 作為快取淘汰策略

智慧快取策略#

根據 80-20 法則:每日 20% 的影片讀取量產生 80% 的流量。因此可以嘗試快取每日 20% 的影片讀取量及其 Metadata。

內容傳遞網路(CDN)#

CDN 是一個分散式伺服器系統,根據使用者的地理位置、網頁來源與內容傳遞伺服器來傳遞網頁內容。

CDN 的優勢#

  • CDN 在多個地點複製內容,影片更有可能靠近使用者,經過較少的網路跳轉,從更友善的網路串流
  • CDN 機器大量使用快取,大部分影片可以直接從記憶體提供

較不熱門的影片(每日 1-20 次觀看)不會被 CDN 快取,由各資料中心的伺服器提供服務。

容錯(Fault Tolerance)#

使用 Consistent Hashing 在資料庫伺服器間進行分佈。Consistent Hashing 不僅有助於替換故障伺服器,也能在伺服器間分散負載