動画配信と Amazon ECS と Google Kubernetes Engine (GKE)

インフラエンジニアのほりぐちです。この文章は、ウェブページやゲームの API のようにリクエストを受け取ってレスポンスを返すだけのサーバとは全く違う用途において、コンテナで解決しようとしてみた感想です。長くなるので用語や機能の解説は省略しています。


近頃は VTuber 配信も始めて同時視聴一万人オーバーでもそこそこの遅延と画質でお届けできるようになりました。実装では IaaS を全く使わずにすべてコンテナか PaaS のマネージドサービスを利用しています。また、サービスとしてはライブ配信のみを行い、アーカイブの配信は行っていません。


VTuber 文化は視差つきヘッドセットをかぶって体験する流れと、動画配信プラットフォームに動画として届ける流れがあるようです。配信技術的も多様で、キャラクターのアニメーションや音声等のデータを配信するパターンと、動画として出来上がった画面を配信し、そのほかメタデータは別チャンネルで配信するパターンになってます。

動画 メタデータ
主な内容 映像、音声 アニメーション、チャット、音声
技術 ほとんどオープン(パテント) ほとんど独自
主なプロトコル RTMP,HTTPやWebSocketなど おそらく独自(TCPやUDP)
遅延 数秒~10秒前後 1秒未満
大容量、アーカイブが容易、他プラットフォーム対応しやすい 専用プレイヤー、独自視点や視差付き360度可能

個人的にはマルチプレイ系ネトゲが好きなんでメタデータ系の技術が得意なんですが、今の Reality では実装速度や汎用性を重視して動画配信パターンを採用してます。具体的には以下のような構成で、動画配信周りでは Kubernetes ( 以下 GKE) を多く活用しています。

そこで過去の記事では Amazon ECS (以下 ECS ) を使って WebSocket を扱い、その具合の良さに驚いていましたが、今回 GKE で構築したことにより ECS に想いをはせてみたり、使ってみた感想をまとめてみたいと思います。

コストパフォーマンスや機能などの定量的な評価ではなく、個人的な主観によるものです。

ライブ動画エンコードについて

ライブ動画なので、パイプラインのいずれかが2秒ほど止まってしまうと動画が途切れてしまいます。ここはサービスの安定性とパフォーマンスを相談しながら調整できるポイントなのですが、非常に重要な要素であると思います。また、ライブ動画なので、一度開始すると数十分~数時間の配信を行います。よくある API 実装と比較すると気持ち的に次のような感じです。

ライブ配信 API
1リクエスト処理が終わるまで 数分~数時間 おおむね1秒未満
並列リクエスト数 配信する人数まで 大量
エラーの許容 ちょっとでも止まるとダメ 比較的ゆるめ

ゲーム API の場合は利用者が多く、利用者間の依存が低いので、一人の不具合が大勢に伝わることは稀ですが、ライブ画配信では配信者の不具合がすぐに大勢に伝わってしまうため、非常に神経質に扱っています。

こういった神経質な用途は動画配信だけでなく、 MMORPG 等の一つのチャンネルやゾーンでも不具合があると大量のプレイヤーにすぐに影響が出てしまうので性質は似てます。一方でコンテナ技術を中心にした Kubernetes では長時間リクエストを処理したりオンメモリ重視のコンテンツなどのサービスは Immutable Infrastructure の文化とあまり合わないと考えられているのか、それに向いた機能は少な目です。特に Pods はホストと分離するためには大変すばらしい概念と機能ですが、長時間一つの Pods を占有し、内部の状態だけで完結させるような用途はとても難しいと感じています。

逆説的ですが、そもそも ECS の Task はもう少し Amazon EC2 を中心に AWS 全体と密になっていて細かくコントロールしなければならず、むしろ AWS Lambda を使って Mutable なインフラを作りやすいイメージがあります。そもそも Lambda が優秀ですし、 Lambda は ECS に依存していないので、うまくレイヤーを分けることができました。

Pods と Task

  • Pods には ReplicaSet と更にそれをコントロールする Deployments があります。いずれも Immutable で短時間リクエストをバリバリ処理するには向いています。 ECS には Service として両方がまとまっているので、より細かく制御するなら Lambda を使うし、実装しやすいです。
  • Pods は Task より抽象度が高く sidecar との通信なども難なくクローズにできますが、 Task ではホストの TCP 資源が Task 同士で競合します。 Pods はコンテナホストに依存せずに kube-proxy 経由で運用できますが、ちょっとホストに依存したいときには Task のほうが抽象度が低くて扱いやすいです。
  • GKE の Service では Pods にランダムでリクエストが割り振られますが、チャットのように長時間居座るケースと相性が悪いです。あとからいくら Pods を追加しても起動時間の長い Pods がリソース不足になってしまいます。 Task では ELB に Target Group を大量にセットすることで、アプリケーション側でコンテナへの流量を制御しやすいように見えます。

不具合、障害、機能不足など

  • Kubernetes で機能が合わないときには拡張することができますが、むしろ OSS を拡張しなければならず、そんなにやる気あるなら ECS & Lambda か IaaS で良い気がします。
  • いずれも致命的なバグを踏む可能性はありますが、 GKE のほうは Kubernetes エコシステムに不具合があればサービスが止まってしまうし、クラスターの修正が困難になるかもしれず(実際に kube-proxy の全滅や kube-dns がサチったり gce-ingress バグ対応で修正すら動作しなくなることも)。たぶん ECS は Amazon さんに何とかしてもらえると思います。
  • 一方で ECS のほうはどんなに頑張っても CloudFormation 一発でサービスが新規にデプロイできるかというとすごい労力が必要になりますし、 Kubernetes のほうは GKE Cluster や IAM 以外は yaml をとっておけばよいのでサービス全体の作り直しも比較的現実的かと思います。
  • ECS には RBAC 相当の仕組みはないけど、むしろ IAM 直結なので AWS の一部として扱いやすかったです。 GKE では RBAC と IAM の二つのレイヤーがあって理解しにくいんですが、 G-Suite アカウントも IAM に使えるのでヒトとの連携はしやすいです。
  • ECS では ec2-user でログインして直感的にホスト側を扱いやすく、 GKE では大半のことが kubectl でできるしホスト側は CoreOS toolbox なので慣れれば調査しやすいです。

まとめ

そもそも動画配信やチャットといった寿命の長いリクエストと Immutable や AutoScale の考えは相性が悪いので、どちらを選択しても工夫する必要があります。なので OSS で Go を書き足していくか、部分的に AWS Lambda を書いていくか、好きなほうを選択したらよいんじゃないかと思います。

また、サービス開始からライブ配信のみ、誰でも配信できるという環境をコンテナ関連技術で組んでるケースが少なすぎる寂しさと、需要の低さがあるのでぜひみんなも試してみてください( EKS on Fargate あたりで)。


REALITY はもちろん、インフラ部でも積極採用中です! VTuber やインフラ、動画配信に興味ある方はぜひ応募よろしくお願いします。
https://corp.gree.net/jp/ja/recruit/