Upgrade to Pro — share decks privately, control downloads, hide ads and more …

agones 上に作る QUIC を使った音声通信機能【MIXI TECH CONFERENC...

agones 上に作る QUIC を使った音声通信機能【MIXI TECH CONFERENCE 2023】

MIXI TECH CONFERENCE 2023
にてお話した古城の資料です。

動画:https://youtu.be/kqx3dZmZ7u4
セッション詳細:https://techcon.mixi.co.jp/2023/d1-2

MIXI ENGINEERS

March 02, 2023
Tweet

Video

More Decks by MIXI ENGINEERS

Other Decks in Technology

Transcript

  1. ©MIXI Agenda 1. 課題 • 制作の経緯と解決したかった課題 2. Architecture • クライアントの音声サーバへの接続フロー

    • クラウド上での構成 3. Application • サーバ/クライアントの構成 • 音声データが作成されて送受信をするデータフロー 4. サービス導入 • 技術先行のプロダクトをサービスに組み込む上で行ったこと 5. 今後について 3
  2. ©MIXI 過去のシステム • WebRTC SFUによる音声通信のシステムを開発しており、 XFLAG PARK や モンストフリークなどのゲー ムのユーザイベントに使用

    ◦ 音声同時接続、数万人のイベントにも使用 ◦ Go 製 (pion base) 5 Node001 Node002 room2 room1 Data Store stats reservation room3 Manager API
  3. ©MIXI 改善したい点 • コンテナ仮想化 • ノード作成時にDNS登録やセットアップの処理が発生 ◦ コンテナをDeployのみでスケールも行いたい • 1

    roomを一つのコンテナとして運用したい ▪ 音声サーバのコードから room管理を除外できる • ノードの管理とクライアントの接続先の管理の簡略化 ◦ データベースにノードや接続先の情報を保存していた ◦ 自前で管理しているものをなるべく減らしたい 7 VM Node001 room2 room1 VM Node002 room3 Container001 Container002 Container003 room1 room2 room3
  4. ©MIXI アイデア • 音声用サーバに必要な要件はゲームサーバと似ている ◦ 必要に応じてリソースを確保 /解放する ◦ 参加者の接続先の管理ができる必要がある •

    ゲームサーバをKubernetes上でホスティングする良いソリューションはないか? • Agones ◦ コンテナ型仮想化でホスティング ◦ オートスケールの仕組みもあるので、スケールの設定も可能 8
  5. ©MIXI Agones • Kubernetes上でゲームサーバをホスティングするためのライブラリ ◦ 中身はKubernetesのCRDとカスタムコントローラ, SDK • 提供される主な機能 ◦

    ゲームサーバのライフサイクルと在庫の管理 ◦ podの状態を変更するためのSDK ◦ podごとに異なる外部portの割り当て 9 Agones controller state: allocated port: 9800 state: ready port: 9801 state: ready port: 9802 state: ready port: 9803 game server SDK sidecar Kubernetes API fleet Scheduled Ready Allocated Shutdown
  6. ©MIXI 改善したい点 • 複数サービスに基盤的に提供 ◦ 複数のサービスが相乗りでき、使用量を補足できる仕組み ◦ 無停止でバージョンアップができるようにしたい • 通信量の削減

    ◦ 一番コストに関係してくる部分でできる限り減らしたい ◦ 接続人数が増えるとそれぞれ下りのデータが一人分増えるので人数が多い部屋だと通信量が どんどん増えてしまう 10 Room 001 Room 001 参加者: 3名 上り: 3本 下り: 6本 参加者: 4名 上り: 4本 下り: 12本
  7. ©MIXI 技術的投資 • たんぽぽグループの現在のミッションは弊社で必要になりそうな技術に対する知見を深め、 それをサービスに還元していくこと ◦ 昔は「刺身の上にたんぽぽを乗せるような仕事をなくす」でした (技術的負債を解消する ) •

    音声通信は弊社で届けたい価値を提供する上で必要な要素 ◦ 音声通信に関する知見を深めておきたい • 既存の問題の解決と同時に新規技術の検証をまとめて行いたい ◦ 通信周りの新しいプロトコルも確認しておきたい ▪ QUICを選択(使ってみたい ) 11
  8. ©MIXI 接続フロー 13 servcie api allocator proxy (api server) ku

    allocator (Service) Agones controller aria-server state: ready port: 9800 aria-server state: ready port: 9801 Kubernetes aria side service side Agones
  9. ©MIXI 接続フロー 14 servcie api allocator proxy ku allocator Agones

    controller aria-server state: ready port: 9800 aria-server state: ready port: 9801 Kubernetes aria side service side Agones • 特定のクライアントを特定のルームに参加させたい • serviceは allocator proxyにリクエスト ◦ parameter は roomIDとuserID (string) ◦ このリクエストは認証有 • allocator proxyは serviceIDとroomIDで複数の Kubernetes cluster からConsistentHashigによりクラス タを決定する ◦ roomとclusterのマッピングは持ちたくない ◦ クラスタ入れ替えのために少し工夫が必要
  10. ©MIXI 接続フロー 15 servcie api allocator proxy ku allocator Agones

    controller aria-server state: ready port: 9800 aria-server state: allocated port: 9801 aria-server state: ready port: 9802 Kubernetes aria side service side Agones • allocator は serviceIDとroomIDを使ってAgonesに対してPodの確保を依頼 ◦ StateAllocationFilter を使用することでFindOrAllocate をリクエスト ◦ 後から参加するユーザも同じ roomへの接続を誘導 • pod allocationの際にAgonesのサーバのメタデータに必要な情報を更新 ◦ serviceID, roomID, 認証のSecret • 確保された音声サーバは内部で SDK経由でメタデータの更新を watchしており、内部の configurationを更新
  11. ©MIXI 接続フロー 16 servcie api allocator proxy ku allocator Agones

    controller aria-server state: ready port: 9800 Kubernetes Agones aria side service side aria-server state: allocated port: 9801 aria-server state: ready port: 9802 • allocator はagonesから帰ってきた情報から tokenを作成 ◦ serviceID, roomID, userIDや有効期限を含んだ署名付きの JWT • tokenと接続先の情報を返却
  12. ©MIXI 接続フロー 17 servcie api allocator proxy ku allocator Agones

    controller aria-server state: ready port: 9800 Kubernetes aria side service side Agones aria-server state: allocated port: 9801 • client は受け取ったtokenを使って音声サーバと接続を開始 • 音声サーバはtokenの検証を行い、クライアントの認証を実施 ◦ 認証が成功すれば接続は完了です • 音声サーバにクライアントからの接続がこなかった場合は、 一定期間経過後に音声サーバが自らリソースを解放します aria-server state: ready port: 9802
  13. ©MIXI マルチクラスタの運用 • マルチクラスタにした理由 ◦ Kubernetesはpodがある一定数を超えるとパフォーマンスが低下する ◦ Agonesの処理がボトルネックになったときに逃げ道が欲しい • ConsistentHashを使ったルーティングのデメリット

    ◦ 要素の数や順番が変わってしまうと一貫性がなくなる ◦ 単純にクラスターを増やそうとすると変更前の podへの接続ができなくなる • 2つのCLUSTER Configurationを使ってクラスタの入れ替えをサポート ◦ CURRENT_CLUSTERS ▪ 通常使用しているクラスターのリスト ◦ OLD_CLUSTERS ▪ 過去に使用していたクラスターのリスト 18
  14. ©MIXI マルチクラスタの運用 • allocation-proxy はOLD_CLUSTERSの設定がある場合は、そのリストを使ってから Find ◦ 起動済みのpodがあった場合はそちらを接続先として返します ◦ 見つからない場合は通常の

    CURRENT_CLUSTERSへのFindOrAllocate を実施します • OLD_CLUSTERSのpodの切断が確認できたら OLD_CLUSTERSの設定を削除します ◦ クラスター内のメタデータをフィルタしたりログから確認が可能 19 allocator proxy current Kubernetes clusters old Kubernetes clusters Find FindOrAllocate
  15. ©MIXI クラウド上の構成 20 aria-allocator-proxy Cloud Run Kubernetes / aria-cluster-0 Kubernetes

    / aria-cluster-1 Kubernetes / aria-cluster-N aria-allocator Service/Deployment agones-system controller Service/Deployment aria-server(Ready) Pod aria-server(Allocated) Pod aria-server(Allocated) Pod fleet (aria-server) Agones Cloud Storage BigQuery Logging
  16. ©MIXI server • サーバはElixir+Rustで実装 ◦ 採用理由は ▪ 弊社にElixirの知見があること ▪ Discordも同様の構成で実績あり

    ▪ RustのQUICライブラリ、cloudflare/quiche を使用したかった • ここまでQUICと言ってきたが、正確には WebTransport Over http/3 • WebTransportの実装はドラフトを参照して、 quicheにパッチを当てて利用 ◦ Elixirから WebTransport Server を動かすためのフレームワークは公開しています ▪ https://github.com/xflagstudio/requiem ◦ コネクションの管理や Agonesとの通信をElixirで実装 ◦ QUICのパケット処理をRustで実装 ◦ 録音機能も実装 23
  17. ©MIXI client • 音声パケットの処理部分は Rustで実装 ◦ QUICパケットの処理はサーバと同様に cloudflare/quicheを使用することで内部実装の一致を保 証 ▪

    QUICは比較的新しいプロトコルなので、異なるライブラリ間でのトラブルを回避 • 使用するサービスのエンジニアが開発環境でも動作確認が必要なため、 Win, OSXもサポート ◦ OSXはAppleSillicon移行期のためBundleで (x86_64, arm64) 両対応 • iOSは静的ライブラリにビルドしたものを Framework化してうえで関数呼び出ししています ◦ サービス側のクライアントで使用する BoringSSL/OpenSSLとのシンボル衝突を回避するため 24
  18. ©MIXI 音声データフロー 25 Unity Recorder Resampler Buffering Packetizer Codec Denoiser

    GameObject AudioPlayer (UnityAudio, CRIWare) Audio Mixier QUIC Server Member Management Jitter Buffer Network Voice Processing 音声データフロー
  19. ©MIXI 音声データフロー 26 Unity Recorder Resampler Buffering Packetizer Codec Denoiser

    GameObject AudioPlayer (UnityAudio, CRIWare) Audio Mixier QUIC Server Member Management Jitter Buffer Network Voice Processing • AudioInput 部分 • Recorder ◦ Bluetoothの処理やエコキャンの処理を担当している • Resampler ◦ マイクデバイスごとに異なるサンプリングレートのデータを OPUSで必要な48,000Hzに統一 • マイク関連はトラブルが多いので別ライブラリとして 作成している ▪ Serenade ▪ (抱えていた問題はAppendix に記載しておきます )
  20. ©MIXI 音声データフロー 27 Unity Recorder Resampler Buffer Packetizer Codec Denoiser

    GameObject AudioPlayer (UnityAudio, CRIWare) Audio Mixier QUIC Server Member Management Jitter Buffer Network Voice Processing • データ処理部分 • 適切なフレーミングのため Bufferがある • DenoiserにはRNNoise • CodecはOPUSを使用 ◦ FEC(前方誤り訂正)とDTX(不連続送信)を 設定している ◦ DTXで通信量を削減 • Packetizerでパケットを作成している ◦ RTPをアレンジしたものを使用
  21. ©MIXI 音声データフロー 28 Unity Recorder Resampler Buffering Packetizer Codec Denoiser

    GameObject AudioPlayer (UnityAudio, CRIWare) Audio Mixier QUIC Server Member Management Jitter Buffer Network Voice Processing • 通信部分 • 認証情報や接続維持、切断検知はストリーム上で行う • PacketizerからもらったPacketはデータグラム として送信される • 送信は自分の分だけだが、受信は roomのメンバーの人数だけ受け取る
  22. ©MIXI 音声データフロー 29 Unity Recorder Resampler Buffering Packetizer Codec Denoiser

    GameObject AudioPlayer (UnityAudio, CRIWare) Audio Mixier QUIC Server Member Management Jitter Buffer Network Voice Processing • 受け取ったPacketからroom内のメンバーごとに バッファにデータを整理する • JitterBufferでパケットの遅延や順序ずれを吸収 ◦ 一定期間とどかなかったパケットはロスト扱い ◦ 取り出す時にデコード • UnityのGameObjectにアタッチできるAudioPlayer コンポーネントを用意
  23. ©MIXI サービス導入のために • 技術先攻のプロダクト開発 • 開発本部内の定期的な共有会でこういうものを作っていると共有 ◦ 開発本部は各サービスのサポートに人を出している部署なので、 各プロダクトなどにアサインされた人が音声機能が必要なときに声をかけてくれます •

    音声機能を必要としているプロジェクトに相談 ◦ 他社のサービスと料金や機能面での比較を行い、説明をしに向かいます ◦ さすがに予算面で敗北していたり機能が不足している場合は、話が通りません • 導入のためにサービスの開発に参加 ◦ 音声接続の実装だったり、音声接続までに必要なサービス開発の手伝いも行います • サービス側の開発メンバーと協力して、バグを潰しながら安定動作の検証をしていきます。 31
  24. ©MIXI Special Thanks !!! • 技術的なチャレンジの意味を理解し、導入の決断をしてくれたマネジメントの方々 • 今回は試験的な導入であったため、全てのインフラをゴーストスクランブル内で管理しており、 日々運用してくださっているサーバエンジニアの方々 •

    クライアント側のパフォーマンス問題などを一緒に調査解決してくださった クライアントチームの方々 • 端末ごとのスペックの違いによって発生する問題を検証してくださった QAチームの方々 33
  25. ©MIXI 今後 • 実装済みで導入準備中の機能 ◦ 少人数部屋用のpure Rust version ▪ 少人数の部屋の場合

    CPUコアの割り当ても少なく、あまりロックをかけずに一定感覚ごとに まとめてパケットを処理し効率よく CPUを使うような設計 • やりたいこと ◦ Agones の最新への追従 ◦ 社内で気軽にサービスから使える環境の構築 ◦ QUICの知見を生かして、ゲームのリレーサーバの実装 • メンバーが少なく他のプロジェクトに手が取られていて .... ◦ 仲間が増えると良いなと思っています .... 35
  26. ©MIXI 旧チャットの構成 (1)  39 MatchingAPI Node001 Node002 Data Store group2

    group1 nodeは自分の状態(接続数など)を定期的に更新する これが node の health check になる stats reservation group1 is node1. group2 is node2.
  27. ©MIXI 40 MatchingAPI Node001 Node002 Data Store group2 group1 クライアントは接続時に

    MatchingAPIから 接続先を取得し、対象の nodeに接続 MatchingAPIはnodeの状態から接続先を決定し、 groupIDと接続先のマッピングを保存し、 クライアントに返す stats reservation group1 is node1. group2 is node2. group3 どこ? 旧チャットの構成 (2)
  28. ©MIXI 41 MatchingAPI Node001 Node002 Data Store group2 group1 stats

    reservation group1 is node1. group2 is node2. group3 同じgroupに接続するクライアントは MatchingAPIから既に存在する接続先を 取得して繋ぎにいく group3 どこ? 旧チャットの構成 (3)
  29. ©MIXI 42 MatchingAPI Node001 Node002 Data Store group2 group1 stats

    reservation group1 is node1. group2 is node2. group3 is node3. group3 同じgroupに接続するクライアントは MatchingAPIから既に存在する接続先をも らって繋ぎにいく 同じhostで複数のチャットグループに機能を提供することで、 connectionMapping, roomMappingなどの管理データが増えロックも存在する 旧チャットの構成 (4)
  30. ©MIXI 43 MatchingAPI Node001 Node002 Dead! Data Store group1 stats

    reservation group1 is node1. group2 is node2. group3 is node3. group3 nodeを追加するとサーバが readyになるとstats が更新されて振り分け対象になる Node003 New! Reconciler Worker statsの更新時刻を監視し、更新がない nodeを削除し、その nodeに紐づくreservationを削除する これで障害nodeへの接続を排除する 旧チャットの構成 (5)
  31. ©MIXI マイク関連のトラブル (1) 44 • 録音開始する際にStreamをどう扱うかのmodeの選択が可能 • NormalModeのまま録音するとAEC、AGC、NSの恩恵が受けられない • CommunicationModeで開始すると、メインがVoiceCallになり、ゲーム側音量の調整ができなくなる

    Game内の音楽 Music Stream VoiceCall Stream Game内の音楽 Music Stream VoiceCall Stream マイク入力 Game内の音楽 • 録音を開始すると、OS から見て音のStreamが二つになります 簡略化したAndroidの例