在本章中,要請你設計 YouTube。這個題目的解法可以套用到其他面試題目,例如設計影片分享平台像 Netflix 與 Hulu。圖 1 顯示了 YouTube 首頁。

圖 1

YouTube 看起來很簡單:內容創作者上傳影片,觀眾按下播放。真的有那麼簡單嗎?並非如此。在簡單的外表底下有許多複雜的技術。讓我們看看 2020 年 YouTube 一些令人印象深刻的統計數字、人口統計與有趣事實 [1] [2]:

  • 月活躍使用者總數:20 億
  • 每日觀看影片數:50 億
  • 73% 的美國成人使用 YouTube
  • YouTube 上有 5,000 萬位創作者
  • YouTube 在 2019 年的廣告收入為 151 億美元,比 2018 年成長 36%
  • YouTube 占所有行動網路流量的 37%
  • YouTube 提供 80 種不同語言

從這些統計數字,我們知道 YouTube 規模龐大、跨越全球,並且賺很多錢。

Step 1 - Understand the problem and establish design scope#

如圖 1 所示,除了觀看影片之外,你還可以在 YouTube 上做很多事。例如,留言、分享或對影片按讚、將影片儲存到播放清單、訂閱頻道等。在 45 或 60 分鐘的面試中設計所有東西是不可能的,因此問問題以縮小範圍很重要。

應徵者:哪些功能很重要?

面試官:上傳影片與觀看影片的能力。

應徵者:我們需要支援哪些 client?

面試官:行動 App、瀏覽器與智慧型電視。

應徵者:我們有多少日活躍使用者?

面試官:500 萬。

應徵者:使用者每日在產品上花的平均時間是多少?

面試官:30 分鐘。

應徵者:我們需要支援國際使用者嗎?

面試官:是的,很大比例的使用者是國際使用者。

應徵者:支援哪些影片解析度?

面試官:系統接受大多數的影片解析度與格式。

應徵者:是否需要加密?

面試官:是的。

應徵者:影片有檔案大小要求嗎?

面試官:我們的平台專注於小型與中型影片。允許的最大影片大小為 1GB。

應徵者:我們可以利用 Amazon、Google 或 Microsoft 提供的現成雲端基礎設施嗎?

面試官:很棒的問題。對大多數公司來說從零開始建構所有東西不切實際,所以建議利用現成的雲端服務。

在本章中,我們專注於設計具備以下功能的影片串流服務:

  • 快速上傳影片的能力
  • 流暢的影片串流
  • 變更影片畫質的能力
  • 低基礎設施成本
  • 高可用性、可擴展性與可靠性需求
  • 支援的 client:行動 App、瀏覽器與智慧型電視

Back of the envelope estimation#

以下估算是基於許多假設的,所以與面試官溝通以確保她有共識很重要。

  • 假設產品有 500 萬日活躍使用者(DAU)。
  • 使用者每天觀看 5 部影片。
  • 10% 的使用者每天上傳 1 部影片。
  • 假設平均影片大小為 300 MB。
  • 每日所需總儲存空間:500 萬 _ 10% _ 300 MB = 150TB。
  • CDN 成本:
    • 當雲端 CDN 提供影片時,你會為從 CDN 傳輸出去的資料付費。
    • 讓我們以 Amazon 的 CDN CloudFront 來估算成本(圖 2)[3]。假設 100% 流量都從美國提供。每 GB 平均成本為 0.02 美元。為了簡化,我們只計算影片串流的成本。
    • 500 萬 _ 5 部影片 _ 0.3GB * 0.02 美元 = 每天 150,000 美元。

從粗略的成本估算中,我們知道從 CDN 提供影片要花很多錢。即使雲端供應商願意為大客戶大幅降低 CDN 成本,成本仍然很可觀。我們會在 deep dive 中討論減少 CDN 成本的方法。

圖 2

Step 2 - Propose high-level design and get buy-in#

如先前所討論,面試官建議利用現有的雲端服務而不是從零開始建構所有東西。CDN 與 blob storage 是我們會使用的雲端服務。有些讀者可能會問為什麼不自己建構所有東西?原因如下:

  • 系統設計面試不是要從零開始建構所有東西。在有限的時間內,選擇正確的技術做好工作比詳細解釋技術如何運作更重要。例如,提到使用 blob storage 來儲存原始影片就足以應付面試。談論 blob storage 的詳細設計可能太過頭了。
  • 建構可擴展的 blob storage 或 CDN 極為複雜且昂貴。即使是 Netflix 或 Facebook 這樣的大公司也不會自己建構所有東西。Netflix 利用 Amazon 的雲端服務 [4],而 Facebook 使用 Akamai 的 CDN [5]。

在高階層次上,系統由三個元件組成(圖 3)。

圖 3

  • Client:你可以在電腦、手機與智慧型電視上觀看 YouTube。
  • CDN:影片儲存在 CDN 中。當你按下播放時,影片會從 CDN 串流。
  • API 伺服器:除了影片串流之外的所有東西都會經過 API 伺服器。包括動態消息推薦、產生影片上傳 URL、更新中繼資料資料庫與快取、使用者註冊等。

在問答時段中,面試官對兩個流程感興趣:

  • 影片上傳流程
  • 影片串流流程

我們會探索這兩個流程的高階設計。

Video uploading flow#

圖 4 顯示了影片上傳的高階設計。

圖 4

它由以下元件組成:

  • 使用者:使用者在電腦、手機或智慧型電視等裝置上觀看 YouTube。
  • Load balancer:load balancer 將請求平均分配給 API 伺服器。
  • API 伺服器:除了影片串流,所有使用者請求都會經過 API 伺服器。
  • Metadata DB:影片中繼資料儲存在 Metadata DB 中。它經過 sharding 與 replication 以滿足效能與高可用性需求。
  • Metadata cache:為了更好的效能,影片中繼資料與使用者物件會被快取。
  • Original storage:使用 blob 儲存系統來儲存原始影片。Wikipedia 中關於 blob storage 的引述顯示:「Binary Large Object(BLOB)是儲存在資料庫管理系統中作為單一實體的二進位資料集合」[6]。
  • 轉碼伺服器(Transcoding servers):影片轉碼也稱為影片編碼。它是將一種影片格式轉換為其他格式(MPEG、HLS 等)的過程,這些格式為不同裝置與頻寬能力提供最佳的影片串流。
  • 轉碼後儲存(Transcoded storage):這是儲存轉碼後影片檔案的 blob storage。
  • CDN:影片快取在 CDN 中。當你按下播放鈕時,影片從 CDN 串流。
  • 完成佇列(Completion queue):這是一個訊息佇列,儲存有關影片轉碼完成事件的資訊。
  • 完成處理器(Completion handler):這由一組 workers 組成,從完成佇列中拉取事件資料,並更新中繼資料快取與資料庫。

既然我們了解了每個元件,讓我們檢視影片上傳流程是如何運作的。流程被拆解為兩個並行進行的程序:

  • a. 上傳實際影片。
  • b. 更新影片中繼資料。中繼資料包含影片 URL、大小、解析度、格式、使用者資訊等。

Flow a: upload the actual video#

圖 5

圖 5 顯示了如何上傳實際影片。說明如下:

  1. 影片被上傳到 original storage。
  2. 轉碼伺服器從 original storage 抓取影片並開始轉碼。
  3. 轉碼完成後,以下兩個步驟並行執行:
    • 3a. 轉碼後的影片被送到 transcoded storage。
    • 3b. 轉碼完成事件被排入 completion queue。
      • 3a.1. 轉碼後的影片被分發到 CDN。
      • 3b.1. Completion handler 包含一組 workers,持續從佇列中拉取事件資料。
      • 3b.1.a. 與 3b.1.b. 影片轉碼完成時,completion handler 更新中繼資料資料庫與快取。
  4. API 伺服器告知 client 影片已成功上傳並可開始串流。

Flow b: update the metadata#

當檔案正被上傳到 original storage 時,client 並行送出一個請求來更新影片中繼資料,如圖 6 所示。請求包含影片中繼資料,包括檔名、大小、格式等。API 伺服器更新中繼資料快取與資料庫。

圖 6

Video streaming flow#

每當你在 YouTube 上觀看影片時,它通常會立即開始串流,你不用等到整部影片下載完成。

下載指的是整部影片被複製到你的裝置,而串流指的是你的裝置從遠端的原始影片持續接收影片串流。當你觀看串流影片時,client 一次載入一點點資料,讓你可以立即且持續觀看影片。

在我們討論影片串流流程之前,讓我們看一個重要的概念:串流協定(streaming protocol)。這是控制影片串流資料傳輸的標準化方式。受歡迎的串流協定有:

  • MPEG–DASH。MPEG 代表「Moving Picture Experts Group」,DASH 代表「Dynamic Adaptive Streaming over HTTP」。
  • Apple HLS。HLS 代表「HTTP Live Streaming」。
  • Microsoft Smooth Streaming
  • Adobe HTTP Dynamic Streaming(HDS)

你不需要完全了解或記住這些串流協定的名稱,因為它們是需要特定領域知識的低階細節。重要的是要理解不同的串流協定支援不同的影片編碼與播放器。當我們設計影片串流服務時,必須選擇正確的串流協定來支援我們的使用案例。要了解更多串流協定,這裡有一篇很棒的文章 [7]。

影片直接從 CDN 串流。離你最近的 edge server 會傳遞影片,因此延遲很低。圖 7 顯示了影片串流的高階設計。

圖 7

Step 3 - Design deep dive#

在高階設計中,整個系統被拆分為兩部分:影片上傳流程與影片串流流程。在本節中,我們會以重要的最佳化方法來改良這兩個流程,並介紹錯誤處理機制。

Video transcoding#

當你錄製影片時,裝置(通常是手機或相機)會給影片檔案一個特定的格式。如果你想讓影片在其他裝置上順暢播放,影片必須被編碼為相容的位元率(bitrate)與格式。Bitrate 是位元被處理的速率。較高的 bitrate 通常代表較高的影片畫質。高 bitrate 的串流需要更多的處理能力與快速的網路速度。

影片轉碼很重要,原因如下:

  • 儲存空間:原始影片占用大量儲存空間。一小時長、以每秒 60 幀錄製的高畫質影片可能占用數百 GB 的空間。
  • 相容性:許多裝置與瀏覽器只支援特定類型的影片格式。因此,為了相容性,將影片編碼為不同格式很重要。
  • 頻寬適配:為了確保使用者觀看高畫質影片同時保持流暢播放,最好為網路頻寬高的使用者提供較高解析度的影片,為網路頻寬低的使用者提供較低解析度的影片。
  • 動態切換:網路狀況可能會變化,特別是在行動裝置上。為了確保影片可以連續播放,根據網路狀況自動或手動切換影片畫質對流暢的使用者體驗至關重要。

有許多種編碼格式可用;然而,大多數都包含兩個部分:

  • Container:這就像是一個籃子,包含影片檔案、音訊與中繼資料。你可以從副檔名判斷 container 格式,例如 .avi、.mov 或 .mp4。
  • Codecs:這些是壓縮與解壓縮演算法,目的是減小影片大小同時保留影片品質。最常用的影片 codecs 是 H.264、VP9 與 HEVC。

Directed acyclic graph (DAG) model#

影片轉碼在計算上很昂貴且耗時。此外,不同的內容創作者可能有不同的影片處理需求。例如,有些內容創作者要求在影片上加浮水印,有些自己提供縮圖,有些上傳高畫質影片,而其他人則否。

為了支援不同的影片處理流程並維持高並行性,加入某種程度的抽象並讓 client 程式設計師定義要執行哪些任務很重要。例如,Facebook 的串流影片引擎使用**有向無環圖(directed acyclic graph,DAG)**程式設計模型,將任務以階段定義,使其可以順序或並行執行 [8]。在我們的設計中,我們採用類似的 DAG 模型來達到彈性與並行性。圖 8 表示影片轉碼的 DAG。

圖 8

在圖 8 中,原始影片被分成 video、audio 與 metadata。以下是一些可以套用在影片檔案上的任務:

  • Inspection:確保影片品質良好且未損毀。
  • Video encodings:影片被轉換以支援不同的解析度、codec、bitrate 等。圖 9 顯示了影片編碼檔案的範例。
  • Thumbnail:縮圖可以由使用者上傳或由系統自動產生。
  • Watermark:影片上方的影像疊層,包含關於你影片的識別資訊。

圖 9

Video transcoding architecture#

利用雲端服務的影片轉碼架構提案如圖 10 所示。

圖 10

該架構有六個主要元件:preprocessor、DAG scheduler、resource manager、task workers、temporary storage 以及作為輸出的 encoded video。讓我們仔細看看每個元件。

Preprocessor#

圖 11

Preprocessor 有 4 項職責:

  1. 影片切割:影片串流被切割或進一步切割為更小的 Group of Pictures(GOP)對齊塊。GOP 是以特定順序排列的一組/一塊 frame。每塊都是獨立可播放的單位,通常為幾秒長。

  2. 舊裝置相容:一些舊的行動裝置或瀏覽器可能不支援影片切割。Preprocessor 為舊 client 以 GOP 對齊方式切割影片。

  3. DAG 產生:Processor 根據 client 程式設計師寫的設定檔產生 DAG。圖 12 是一個簡化的 DAG 表示,有 2 個節點與 1 條邊:

    圖 12

    這個 DAG 表示是從以下兩個設定檔產生的(圖 13):

    圖 13(來源:[9])

  4. 快取資料:Preprocessor 是切割後影片的快取。為了更好的可靠性,preprocessor 將 GOP 與中繼資料儲存在 temporary storage 中。如果影片編碼失敗,系統可以使用持久化資料進行重試操作。

DAG scheduler#

圖 14

DAG scheduler 將 DAG 圖切割為任務階段,並將它們放入 resource manager 的任務佇列。圖 15 顯示了 DAG scheduler 如何運作的範例。

圖 15

如圖 15 所示,原始影片被切割為三個階段:階段 1:video、audio 與 metadata。Video 檔案在階段 2 進一步被切割為兩個任務:video encoding 與 thumbnail。Audio 檔案需要 audio encoding 作為階段 2 任務的一部分。

Resource manager#

圖 16

Resource manager 負責管理資源分配的效率。它包含 3 個佇列與一個任務排程器,如圖 17 所示:

  • 任務佇列(Task queue):這是一個優先佇列,包含要執行的任務。
  • Worker queue:這是一個優先佇列,包含 worker 利用率資訊。
  • Running queue:包含目前執行中任務以及執行該任務 worker 的資訊。
  • 任務排程器(Task scheduler):它選出最佳的任務/worker,並指示所選的 task worker 執行該工作。

圖 17

Resource manager 的運作如下:

  • 任務排程器從任務佇列中取得最高優先序的任務。
  • 任務排程器從 worker queue 中取得最佳的 task worker 來執行該任務。
  • 任務排程器指示所選的 task worker 執行任務。
  • 任務排程器將任務/worker 資訊綁定並放入 running queue。
  • 一旦工作完成,任務排程器從 running queue 中移除該工作。

Task workers#

圖 18

Task workers 執行 DAG 中定義的任務。不同的 task workers 可能執行不同的任務,如圖 19 所示。

圖 19

Temporary storage#

圖 20

這裡使用了多個儲存系統。儲存系統的選擇取決於資料類型、資料大小、存取頻率、資料生命週期等因素。例如,中繼資料被 workers 頻繁存取,且資料大小通常很小。因此,將中繼資料快取在記憶體中是個好主意。對於影片或音訊資料,我們把它們放在 blob storage 中。Temporary storage 中的資料會在對應的影片處理完成後被釋放。

Encoded video#

圖 21

Encoded video 是編碼流程的最終輸出。以下是輸出的範例:funny_720p.mp4

System optimizations#

至此,你應該對影片上傳流程、影片串流流程與影片轉碼有了不錯的了解。接下來,我們會以最佳化方法改良系統,包括速度、安全性與成本節省。

Speed optimization: parallelize video uploading#

將影片作為一個整體上傳並沒有效率。我們可以透過 GOP 對齊將影片切割成較小的塊,如圖 22 所示。

圖 22

這允許在先前上傳失敗時可以快速續傳。由 client 實作以 GOP 切割影片檔案的工作可以提升上傳速度,如圖 23 所示。

圖 23

Speed optimization: place upload centers close to users#

另一個改善上傳速度的方法是在全球設置多個上傳中心(圖 24)。在美國的人可以將影片上傳到北美上傳中心,在中國的人可以上傳到亞洲上傳中心。要做到這點,我們使用 CDN 作為上傳中心。

圖 24

Speed optimization: parallelism everywhere#

達到低延遲需要認真努力。另一個最佳化是建構鬆耦合系統並啟用高並行性。

我們的設計需要一些修改才能達到高並行性。讓我們放大來看影片如何從 original storage 傳輸到 CDN 的流程。流程如圖 25 所示,揭示了輸出依賴於前一步驟的輸入。這個依賴性使並行性變得困難。

圖 25

為了讓系統更鬆耦合,我們引入了訊息佇列,如圖 26 所示。讓我們用一個例子來解釋訊息佇列如何讓系統更鬆耦合:

  • 在引入訊息佇列之前,編碼模組必須等待下載模組的輸出。
  • 引入訊息佇列之後,編碼模組不再需要等待下載模組的輸出。如果訊息佇列中有事件,編碼模組就可以並行執行那些工作。

圖 26

Safety optimization: pre-signed upload URL#

安全性是任何產品最重要的面向之一。為了確保只有授權使用者可以上傳影片到正確的位置,我們引入 pre-signed URL,如圖 27 所示。

圖 27

上傳流程更新如下:

  1. Client 對 API 伺服器發出 HTTP 請求以取得 pre-signed URL,這個 URL 給予對 URL 中所識別物件的存取權限。

    Pre-signed URL 一詞是 Amazon S3 上傳檔案時使用的。其他雲端服務供應商可能用不同的名稱。例如,Microsoft Azure blob storage 支援相同的功能,但稱為「Shared Access Signature」[10]。

  2. API 伺服器以 pre-signed URL 回應。

  3. Client 收到回應後,使用 pre-signed URL 上傳影片。

Safety optimization: protect your videos#

許多內容創作者不願在線上發布影片,因為他們擔心原始影片會被偷。為了保護有版權的影片,我們可以採用以下三種安全選項之一:

  • 數位版權管理(DRM)系統:三大 DRM 系統是 Apple FairPlay、Google Widevine 與 Microsoft PlayReady。
  • AES 加密:你可以加密影片並設定授權政策。加密的影片會在播放時解密。這確保只有授權的使用者可以觀看加密的影片。
  • 視覺浮水印:這是影片上方的影像疊層,包含你影片的識別資訊。它可以是公司 logo 或公司名稱。

Cost-saving optimization#

CDN 是我們系統的關鍵元件。它確保影片在全球範圍內快速傳遞。然而,從粗略的成本估算中,我們知道 CDN 很昂貴,特別是當資料量很大時。我們如何降低成本?

先前的研究顯示 YouTube 影片串流呈現長尾分布 [11] [12]。這代表少數熱門影片被頻繁存取,而許多其他影片很少或沒有觀眾。

基於這個觀察,我們實作幾個最佳化:

  1. 只從 CDN 提供最熱門的影片,其他影片從我們的高容量儲存影片伺服器提供(圖 28)。

    圖 28

  2. 對於較不熱門的內容,我們可能不需要儲存許多種編碼後的影片版本。短影片可以隨需編碼。

  3. 有些影片只在某些區域熱門。沒必要將這些影片分發到其他區域。

  4. 像 Netflix 一樣建構自己的 CDN 並與網路服務供應商(ISP)合作。建構自己的 CDN 是個巨大的專案;然而,這對大型串流公司來說可能是合理的。ISP 可以是 Comcast、AT&T、Verizon 或其他網路供應商。ISP 遍布全球並接近使用者。透過與 ISP 合作,你可以改善觀看體驗並降低頻寬費用。

所有這些最佳化都基於內容熱門度、使用者存取模式、影片大小等。在進行任何最佳化之前分析歷史觀看模式很重要。以下是一些關於這個主題的有趣文章:[12] [13]。

Error handling#

對於大規模系統,系統錯誤是不可避免的。要建構高度容錯的系統,我們必須優雅地處理錯誤並快速從錯誤中恢復。

存在兩種類型的錯誤:

  • 可恢復錯誤(Recoverable error):對於可恢復的錯誤,例如影片片段轉碼失敗,一般想法是重試該操作幾次。如果任務持續失敗且系統認為無法恢復,它會回傳適當的錯誤碼給 client。
  • 不可恢復錯誤(Non-recoverable error):對於不可恢復的錯誤,例如損毀的影片格式,系統會停止與該影片相關的執行中任務並回傳適當的錯誤碼給 client。

每個系統元件的典型錯誤由以下手冊涵蓋:

  • 上傳錯誤:重試幾次。
  • 影片切割錯誤:如果舊版本的 client 無法以 GOP 對齊切割影片,整部影片會被傳到伺服器。切割影片的工作改在伺服器端進行。
  • 轉碼錯誤:重試。
  • Preprocessor 錯誤:重新產生 DAG 圖。
  • DAG scheduler 錯誤:重新排程任務。
  • Resource manager 佇列當掉:使用副本(replica)。
  • Task worker 當掉:在新的 worker 上重試任務。
  • API 伺服器當掉:API 伺服器是無狀態的,所以請求會被導向不同的 API 伺服器。
  • Metadata cache 伺服器當掉:資料被多次複製。如果一個節點當掉,你仍然可以存取其他節點來抓取資料。我們可以啟用一個新的 cache 伺服器來取代當掉的伺服器。
  • Metadata DB 伺服器當掉
    • Master 當掉。如果 master 當掉,將其中一個 slave 提升為新的 master。
    • Slave 當掉。如果 slave 當掉,你可以使用另一個 slave 來讀取,並啟用另一個資料庫伺服器來取代當掉的伺服器。

Step 4 - Wrap up#

在本章中,我們呈現了像 YouTube 這樣的影片串流服務的架構設計。如果在面試最後還有額外的時間,這裡有一些其他要點:

  • 擴展 API 層:因為 API 伺服器是無狀態的,所以很容易水平擴展 API 層。
  • 擴展資料庫:你可以談論資料庫複製與 sharding。
  • 直播串流(Live streaming):它指的是影片如何被即時錄製與廣播的過程。雖然我們的系統並不是專為直播串流設計,但直播串流與非直播串流有一些相似之處:兩者都需要上傳、編碼與串流。值得注意的差異是:
    • 直播串流有較高的延遲要求,所以可能需要不同的串流協定。
    • 直播串流對並行性的要求較低,因為小塊的資料已經以即時方式被處理。
    • 直播串流需要不同的錯誤處理。任何花太多時間的錯誤處理都是無法接受的。
  • 影片下架(Video takedowns):違反版權、色情或其他非法行為的影片應被移除。有些可以在上傳過程中由系統發現,而其他可能透過使用者檢舉發現。

恭喜你走到這裡!現在給自己一個鼓勵。做得好!