動画配信のアーキテクチャ図:アップロード、トランスコード、パッケージング、配信

アップロードから再生までの動画配信アーキテクチャ図。マルチパートアップロード、トランスコードのキュー、ABR ラダー、HLS と DASH、DRM、CDN。

· 創業者・開発者

公開日:

動画配信のアーキテクチャ図:アップロード、トランスコード、パッケージング、配信

「YouTube を設計せよ」は人気のあるシステム設計の問題です。面白い部分が、人が予想する場所にないからです。Web サーバーはごく普通です。難しいのは、スマートフォンからストレージへ数ギガバイトを確実に運ぶこと、1 回のアップロードをあらゆる端末と回線で再生できる十数種類のバージョンに変えること、そしてそのバイトを CDN から配信し、自前のサーバーがほとんど目にしないようにすることです。

この記事では、そのパイプラインを順に追います。アップロード、トランスコード、パッケージング、配信です。最後に、そのまま流用できるアーキテクチャ図と、図に書き込むべき判断を示します。

システムは 1 つではなく 2 つ

動画プラットフォームは、1 つのデータベースを共有する 2 つのシステムです。

  • 取り込み: クリエイターがアップロードし、プラットフォームがトランスコードとパッケージングを行います。遅延は分単位で測られ、誰も気にしません。
  • 再生: 視聴者が再生ボタンを押します。最初のフレームは数秒以内に表示されなければならず、止まってはいけません。

この 2 つは 2 本のレーンとして描きます。スケールの基準となるシグナル(1 時間あたりのアップロード数と同時視聴者数)も、障害の起き方も違うからです。

アップロード:API サーバーを経由させない

動画ファイルは大きく、モバイル回線は切れます。そこから 2 つのルールが導かれます。

  1. オブジェクトストレージに直接アップロードする。 アップロード API はクリエイターを認証し、動画のレコードを作成して、署名付き URL を返します。クライアントはバイト列をバケットに直接送ります。API がギガバイト単位のデータを中継することはありません。
  2. 再開できるようにする。 マルチパートアップロードを使い、接続が切れても失敗したパートだけを再試行できるようにします。たとえば Amazon S3 のマルチパートアップロード は、パートを個別にアップロードし、クライアントがアップロードを完了したときに結合します。

アップロードが完了すると、ストレージのイベント(またはクライアントの完了呼び出し)がトランスコードのジョブをキューに入れます。

トランスコード:1 回のアップロードから、アダプティブビットレートのラダーへ

プレイヤーは帯域に応じて画質を切り替えるので、動画はそれぞれ何度もエンコードします。これが アダプティブビットレート(ABR)ラダー です。一般的なラダーは 240p か 360p あたりから 1080p か 4K まであり、段ごとに独自のビットレートを持ちます。

トランスコードは CPU 負荷が高く、並列化がとても簡単です。

  • ソースをキーフレームで区切り、数秒ずつのチャンクに分割する。
  • 各チャンクと各レンディションを、ワーカーフリート上の独立したジョブとしてエンコードする。通常は FFmpeg を使う。
  • 結果をつなぎ合わせるか、セグメントのまま保持する。

そうすれば 2 時間の映画も数時間ではなく数分でトランスコードでき、失敗したジョブは 1 つのチャンクだけを再試行します。ジョブは動画、レンディション、チャンクをキーにして冪等にし、再試行で重複が生まれず上書きされるようにします。

すべてのコンテンツに 1 つのラダーを使うと、ビットを無駄にします。静止したスライドのプレゼンは、サッカーの試合よりはるかに低いビットレートで済みます。Netflix は、動画ごとの複雑さに応じてラダーを選ぶ、タイトル単位のエンコード(per-title encoding)を広めました。最初は固定のラダーで始め、あとからタイトル単位に移行できます。

パッケージング:HLS、DASH、CMAF

プレイヤーは 1 つの大きなファイルをダウンロードするわけではありません。レンディションとセグメントを列挙したマニフェストを読み、数秒ずつのセグメントを普通の HTTP で取得します。

形式 定義 主なプレイヤー
HLS RFC 8216 Apple のデバイス、hls.js などのプレイヤーを使うほとんどのブラウザー
MPEG-DASH ISO/IEC 23009-1 Android、スマートテレビ、dash.js や Shaka Player を使うブラウザー
CMAF ISO/IEC 23000-19 HLS と DASH の両方のマニフェストに使える、1 組の断片化 MP4 セグメント

パッケージャーが重要なのは CMAF のためです。CMAF を使えば、すべての動画を 2 部ずつ持つのではなく、1 組のセグメントを保存して 2 つのマニフェストを書けば済みます。短いセグメントは再生開始が速く、画質の切り替えも早くなります。長いセグメントはリクエスト数が少なく済みます。Apple の HLS オーサリング仕様 には、セグメントの長さ、キーフレーム、ラダーについての具体的な推奨が載っています。

有料コンテンツには DRM が加わります。パッケージャーは共通暗号化(CENC)でセグメントを一度だけ暗号化し、各プラットフォームの DRM システム(Widevine、FairPlay、PlayReady)がライセンスサーバーを通じてプレイヤーにライセンスを発行します。

配信:仕事をするのは CDN

セグメントは静的なファイルであり、そこが要点です。CDN が視聴者の近くでキャッシュするので、人気の動画はほぼすべてエッジキャッシュから配信されます。オリジンはレンディションのバケットで、多くの場合はオリジンシールドの背後に置きます。そうすれば、50 か所のエッジでのキャッシュミスが、ストレージへの 1 回のリクエストにまとまります。

再生 API は小さいままです。視聴者がその動画を見てよいかを確認し、マニフェストの URL を返し(非公開コンテンツなら署名付き)、分析用に再生イベントを記録します。

ライブ配信は別のパイプライン

ライブ動画はパッケージングと CDN を再利用しますが、取り込みは置き換えます。エンコーダーが RTMP や SRT などのプロトコルで取り込みサーバーにストリームを送り、サーバーはラダーをリアルタイムにトランスコードして、数秒ごとに新しいセグメントを書き出します。遅延はセグメントの長さとプレイヤーのバッファーで決まります。HLS と DASH の低遅延モードは、セグメントが完成する前にその一部を届けることで、数秒程度に近づけます。ライブとオンデマンドは、CDN、プレイヤー、メタデータを共有する別々のパイプラインとして保ちます。

アーキテクチャ図

クリエイターはアップロード URL を受け取り、パートを未加工のバケットにアップロードします。バケットはトランスコードのジョブをキューに入れます。ワーカーが各レンディションをエンコードし、パッケージャーがセグメントを別のバケットに書き出して動画を準備完了にします。視聴者はマニフェストを受け取り、CDN から再生し、DRM ライセンスを取得します。

13 個のコンポーネント · 12 個の接続

Archboard で開く
ダイアグラムの内容
  • Creator
  • Upload API
  • Raw uploads
  • Transcode jobs
  • Transcode workers
  • Packager
  • Renditions
  • Video metadata
  • Viewer
  • Playback API
  • CDN
  • DRM license server
  • 1. upload URL
  • 2. multipart
  • 3. done
  • ladder
  • segments
  • ready
  • manifest URL
  • cache miss
  • license
取り込みパイプラインと再生経路に分けた動画プラットフォーム。アップロードはストレージに直接届き、キューがアダプティブビットレートのラダーへのトランスコードを動かし、パッケージャーが HLS と DASH のセグメントを書き出し、視聴者は CDN からストリーミングします。

図の読み方は次のとおりです。

  • 上のレーン、取り込み: クリエイターはアップロード API からアップロード URL を受け取り(1)、未加工のアップロード用バケットにパートを直接アップロードします(2)。完了したアップロードがトランスコードのジョブをキューに入れます(3)。ワーカーがラダーをエンコードし、パッケージャーがセグメントをレンディションのバケットに書き出して、メタデータストアで動画を準備完了にします。
  • 下のレーン、再生: 視聴者は再生 API にマニフェストの URL を要求し、CDN からセグメントをストリーミングします。キャッシュミスのときはレンディションのバケットを読みます。
  • DRM は保護されたコンテンツだけが必要とするので点線です。プレイヤーはライセンスサーバーからライセンスを取得します。
  • Markdown ブロック はラダーの例を示しています。実際の数字は、自分のコンテンツと視聴者の帯域から決めます。

図に載せるべきこと

  • バイトの流れ。 アップロードとセグメントが API を通らず、ストレージと CDN に向かう様子を描きます。
  • ジョブの単位。 「レンディションとチャンクごとに 1 ジョブ」と書けば、再試行と並列性の仕組みがレビュアーに伝わります。
  • 形式と保護。 HLS、DASH、CMAF のどれを使うか、DRM を使うならそれも書きます。
  • 準備完了のシグナル。 パッケージングが終わるまで動画は再生できません。その状態がどこにあるかを示します。

キューとワーカーという同じ形は、イベント駆動アーキテクチャの記事 にも出てきます。クラウド側については、複数リージョンからの配信を AWS のマルチリージョンアーキテクチャ図 で、ワーカーフリートの代わりにストレージのイベントで関数を起動する方法を サーバーレスアーキテクチャ図 で扱っています。

Archboard で作る

  1. Google または GitHub でサインインし、図を作成します。
  2. クリエイターと視聴者用に、C4 モデルパックから 人物 ノードを 2 つ追加します。
  3. アップロード API、トランスコードワーカー、パッケージャー、再生 API 用に コンテナ ノードを、動画のメタデータ用に データベース を追加します。
  4. クラウドパックから オブジェクトストレージ ノードを 2 つと CDN を、トランスコードのジョブ用にデータパックから キュー を、DRM ライセンスサーバー用に 外部システム を追加します。
  5. 取り込みを上のレーンに、再生を下のレーンに描き、エッジにアップロードの手順の番号を付けて、ラダーを書いた基本パックの Markdown ブロックを追加します。

この例で使うダイアグラムノードは 13 個で、Free プランの範囲に収まります。

よくある質問

アダプティブビットレートのラダーとは何ですか? 動画をエンコードするレンディションの一覧で、それぞれが独自の解像度とビットレートを持ちます。プレイヤーは視聴者の回線で維持できる最良のものを選び、帯域が変わるたびに切り替えます。

HLS と DASH のどちらを使うべきですか? 多くの場合は両方です。CMAF のセグメントとして一度だけパッケージングし、HLS と DASH のマニフェストを書けば、2 部保存しなくても Apple のデバイスとほかのプレイヤーの両方に対応できます。

なぜオブジェクトストレージに直接アップロードするのですか? 大きなファイルが API サーバーを通ると、接続とメモリを占有し、接続が切れるとアップロードが最初からやり直しになります。署名付きのマルチパートアップロードならストレージに直接届き、パート単位で再開できます。

トランスコードはどう並列化しますか? ソースをキーフレームでチャンクに分け、各チャンクと各レンディションを別々のジョブとしてエンコードし、結果をつなぎ合わせるかパッケージングします。

動画には CDN が必要ですか? ごく小さな視聴者層を超えるなら必要です。セグメントは静的なファイルなので、CDN は繰り返しのリクエストを、ストレージではなく視聴者に近いキャッシュから返します。

無料で始める — 1 シート、クレジットカード不要。

関連記事

← ブログに戻る

1分でキャンバスを開く

Google または GitHub でサインイン。1シートは無料で、チームが加わったらアップグレード。