Talk given at Architect New World on AWS 2022
Related blog post on AWS blog (my guest post): https://aws.amazon.com/blogs/business-productivity/how-rubykaigi-built-an-event-site-in-days-with-the-amazon-chime-sdk-and-amazon-ivs/
© 2022 Cookpad Inc.RubyKaigi Takeout 2021バーチャル会場 & 配信の技術的舞台裏Sorah Fukumori https://sorah.jp/
View Slide
2021/9 に開催した国際会議 RubyKaigi Takeout 2021 のバーチャル会場を内製した話● 内製までの流れ● 構成の選定● 各種工夫© 2022 Cookpad Inc. 2Agenda
昨年末 AWS Blog に掲載させてもらった内容をより詳細にお届けします(英語版記事を執筆しました)https://aws.amazon.com/blogs/business-productivity/how-rubykaigi-built-an-event-site-in-days-with-the-amazon-chime-sdk-and-amazon-ivs/https://aws.amazon.com/jp/blogs/news/how-rubykaigi-built-an-event-site-in-days-with-the-amazon-chime-sdk-and-amazon-ivs/(25 分しかない割にスライドがめちゃくちゃあるのでサクサク進みます!)© 2022 Cookpad Inc. 3Agenda
● Sorah Fukumori○ https://sorah.jp/○ https://github.com/sorah○ https://twitter.com/sora_h● RubyKaigi Organizer● Senior Software Engineer (Site Reliability, Corporate IT) @ Cookpad● IAM と STS がすき© 2022 Cookpad Inc. 4Who am I
● https://rubykaigi.org● プログラミング言語 Ruby に関する世界最大級の国際会議○ 日本で開催され、近年は東京でなく日本各地で開催中○ 最後の物理開催は RubyKaigi 2019 (福岡)● 参加者は 1,200 人規模● RubyKaigi 2020 は COVID-19 の影響でキャンセルとなりバーチャルへ○ 無料にして YouTube Live を利用○ 従来通りの RubyKaigi と同じ体験ではないことから“RubyKaigi Takeout 2020” として開催© 2022 Cookpad Inc. 5RubyKaigi
● 2021 年もオフラインでの開催は早期に断念● 2020 は緊急避難的に無料かつ YouTube Live で開催したが、2021 は従来通り有料に戻したい○ 有料にすると YouTube Live の選択肢がなくなる● バーチャルカンファレンスのソリューションを探す?○ RubyKaigi 特有の要件を満たす選択肢を検証する余裕は正直ない○ フルタイムで誰かが運営している訳じゃないので© 2022 Cookpad Inc. 6RubyKaigi Takeout 2021
● 複数トラック (2+ セッションが並行できる)● 英語通訳のサポート○ 日本語 → 英語 の同時通訳がある。逆はない● 字幕サポート○ 日本語音声でも英語音声でも 英語字幕のみ 提供● 物理的体験の再現○ Ruby core team や Speaker の名札があったりしていたので、再現したい● スポンサーベネフィット○ 幕間中のロゴ表示や、宣伝テキストの表示を用意したかった○ バーチャルだけでのスポンサーベネフィットを考えるのはかなり難しい…© 2022 Cookpad Inc. 7RubyKaigi のバーチャル会場に求められる要件
● イベントを準備するのが楽しくてやっている Organizer としては物理開催じゃなくなってだいぶ楽しさが減っているなか、バーチャル会場も外から調達してきたらだいぶ楽しくないな…となった● 無茶かもしれないけど作っていい? と聞いて作らせてもらうことに○ 今回はすべて本業の時間にはしなかったのでなかなかしんどかったところはある○ 累計の作業期間は 14~15 日程度© 2022 Cookpad Inc. 8内製への道
● 落ちないでほしい○ しかしオーバープロビジョニングはもったいないしダサい…。● バーチャルカンファレンスのトラフィックとか実績がないし何も分からない○ 信用できるミドルウェアを使う、自前のバックエンドへは出来る限りリクエストをキャッシュ© 2022 Cookpad Inc. 9目標、というかバーチャルならではの要件
● https://github.com/ruby-no-kai/takeout-app● ライブ映像の再生○ 同通バージョン再生のサポート● チャット○ 名前・アイコン・ロール設定○ 現在のスピーカーの強調表示○ モデレーション○ 「RubyKaigi」名義での発言○ 発言のピン止め● 複数トラック● 現在のセッション情報の表示 (他トラックも)● Auto captioning による英語字幕● 幕間映像の生成© 2022 Cookpad Inc. 10作った: takeout-app
© 2022 Cookpad Inc. 11
● 前提: とにかく時間がない○ フルタイムじゃないからね● 慣れた Rails と AWS で作る○ 慣れ、コスト面、アカウント・課金の統一、パフォーマンス・セキュリティへの信頼○ 他の選択肢は学習・検証・金銭コスト含めて高いと判断■ 完璧じゃなくてもユースケースを満たすので OK。すぐに使えるのは大事■ 担当者の慣れというところが大きなファクタだったとは思う© 2022 Cookpad Inc. 12構成
● フロントエンド: React, Chakra UI, useSWR● バックエンド: Rails (Heroku, Heroku PostgreSQL)● 動画: AWS Elemental MediaLive, Chime SDK Messaging● 字幕: Amazon EC2, Amazon Transcribe, Chime SDK Messaging● 配信: Amazon CloudFront (Webのみ)● Ingestion: 物理会場 & 機材© 2022 Cookpad Inc. 13構成
● Amazon Chime が提供している機能を自分のアプリに組込むことができるのが Chime SDK○ いくつかに分割されており、Messaging はチャット機能の提供○ Chime SDK は Chime の名前を冠しているが、ユーザー管理などは Amazon Chime とは一切関係なく利用できる● 選定理由○ 最強とは思わないが我々には必要十分な機能○ 安い。外部の類似 aaS より価格体系がシンプルかつ最低利用額がないのが良い© 2022 Cookpad Inc. 14チャット: Chime SDK Messaging
● Amazon Interactive Video Service○ Twitch で利用されているバックエンドを利用することができるサービス○ 低遅延での動画配信に特化していて非常にシンプル○ 極論、チャンネルを作成すると RTMP URL と HLS playlist URL が出てきて、後は使うだけ● 選定理由○ Elemental MediaLive にはない Web SDK がある■ プレイヤーの実装で考えることが少し減る。Service Worker や wasm などを駆使して低遅延の達成をしていてかっこいい○ プライベート配信の認可が JWT ベースでかんたん○ メタデータ埋め込み配信が便利。SDK で簡単に扱える© 2022 Cookpad Inc. 15動画: Amazon IVS
● IVS に直接出力せず MediaLive を経由○ IVS より前からあるライブ配信や放送用のサービス○ 放送用ということもあり冗長化されたパイプラインや複数の入出力など様々な機能がある一方、そのままでは低遅延にはならないなどの違いがある● 選定理由○ 入力切替がしたい○ 事前に準備した mp4 の再生がしたい○ 字幕のために(後述)音声出力を別に取得したい○ Motion Graphics Overlay 機能を使ってみたい (2021/4リリース, 後述)© 2022 Cookpad Inc. 16動画: AWS Elemental MediaLive
● 音声を与えると文字書き起こしをしてくれるサービス○ ストリーミングでもバッチでもどちらでも対応● RubyKaigi はオフライン開催時から英語字幕の提供をしている○ 現地・アーカイブ動画共に提供。業者へ外注○ 日本語セッションは英語通訳の音声から起こしてもらう○ RubyKaigi Takeout 2021 で自動での実施にトライ● 選定理由○ AWS にあるから (前述の通り)○ テストしたらすんなり上手くいったので○ MediaLive との連携もあり AWS 内に留まって処理できて便利© 2022 Cookpad Inc. 17字幕: Amazon Transcribe
● ご存知 CDN● バックエンドへの TTFB 短縮やアセットファイルの配信・キャッシュに利用○ 今回のバックエンドは us-east-1 にいるため● 選定理由○ AWS にあるから (前述の通り)■ もう少し機能のある CDN の方が負荷対策(後述)に有利だけど、許容© 2022 Cookpad Inc. 18その他: Amazon CloudFront
● RubyKaigi なので● シンプルな Rails アプリケーションでバックエンドを実装○ ログイン・配信状態(セッション内容etc)管理、クライアントへの API token 発行など● デプロイは他に内製しているアプリケーションと揃えるために Heroku○ App Runner の VPC 対応が間に合っていれば採用したかもしれない● API only で残りは React のための HTML を返すだけ© 2022 Cookpad Inc. 19バックエンド: Rails (実装)
● React + react-router + Chakra UI + useSWR● 素朴な SPA として実装● Webpack (+ simpacker) でシンプルにビルドしたものを配信○ Rails との連携は HTTP API さえあればいいので Webpacker とか使わない○ 今なら jsbundling-rails になりそう© 2022 Cookpad Inc. 20フロントエンド: React (実装)
工夫や負荷対策© 2022 Cookpad Inc. 21
● とにかく実績がなくて予測が難しいのでそもそもバックエンドまで届くリクエストを減らしたい○ リクエストが減るとアプリケーションも高速になって嬉しい!● CDN でのキャッシュ、ブラウザのキャッシュ、フロントエンドでのキャッシュや API リクエスト以外でのデータ配信などで大幅にリクエスト数を減らせるようにした○ 現在のセッション情報などを定期的な API リクエストにすると、最大で 1,200 人いることからそこそこの量のトラフィックが来ることになるので考えることが増えてしまう。これを避けたかった© 2022 Cookpad Inc. 22負荷対策: 徹底的なリクエスト数の削減をしたい
● アセットやユーザーアイコン画像のキャッシュはもちろん、それに加えいくつかのバックエンドの API をキャッシュ● 会議進行中に定期的に更新される全ユーザー共通のデータが中心○ 各トラックのセッション情報、配信オンライン状況などのデータ● TTL 短めでキャッシュするようにしている○ データの freshness は高く維持されてほしいため○ キャッシュそのものを返してもらえることより、並行する複数のリクエストをまとめるrequest collapsing の効果に期待© 2022 Cookpad Inc. 23CloudFront でのキャッシュhttps://github.com/ruby-no-kai/takeout-app/blob/25d09cd46cb87a8d42538e1fdb084518aa20aaad/tf/cloudfront.tf
● CDN でキャッシュできるような API に加え、ブラウザにキャッシュさせた API もある (ユーザー固有)○ Chime SDK Messaging で利用する AWS credentials○ Amazon IVS の配信を再生するための JWT● Cache-Control の state-while-revalidate を組み合わせ、バックグラウンドで有効期限が切れる前に早めに新しいものを取得するようにするなども© 2022 Cookpad Inc. 24ブラウザのキャッシュ
● https://swr.vercel.app● React Hook として fetch API などデータ取得ロジックを簡単にラップすることができるライブラリ。付加機能がめちゃくちゃ強力● stale while revalidate の名前を冠する通りキャッシュや非同期 refresh が賢い○ Cache-Control のそれとはあまり関係がない○ ウィンドウをアクティブにした時の再取得や定期的な取得などを簡単に実装できる○ React Hook を良く活かしていて「データ再取得中」の状態をあまり意識しなくてよく、実装がシンプルになるのがポイント○ 気付いたら最新のデータでレンダリングが走ってくれる© 2022 Cookpad Inc. 25useSWR
● 既に取得したデータを再度リクエストすることなく、ブラウザローカルで更新することができる (mutate)○ たとえば write API を実行して得た差分を、そのリソースの read API から得られているデータへマージして、あらためて read API へリクエストせず write した結果をレンダリングさせることができる○ これを Amazon IVS の metadata 配信などで活用© 2022 Cookpad Inc. 26useSWR (2)
● Amazon IVS と Chime SDK Messaging で差分を配信○ IVS は metadata, Chime SDK はチャットメッセージとして○ 現在のセッション情報や、最新の閲覧者数、配信のオンライン状況など● 差分を useSWR の mutate を通して反映○ リクエスト数がグッと減る、というか定期リクエストが完全に不要になる■ しかもリアルタイム性が上がる○ 差分をマージする実装がなかなか大変■ がんばりましょう© 2022 Cookpad Inc. 27IVS と Chime SDK からのリアルタイム更新
● IVS metadata と Chime SDK のメッセージは使い分けていた● 基本 IVS metadata が一番安く配信できる○ 配信の HLS segment を活用しているので効率的○ 送出している映像より先行することがないのもポイント● ただし配信映像を再生していないと降ってこない○ 配信のオンライン状態などは Chime SDK Messaging より送信● サイズが膨れる可能性があるデータも Chime SDK を選択○ IVS metadata は映像に相乗りする都合、サイズ上限・レートリミットも厳しめ© 2022 Cookpad Inc. 28IVS と Chime SDK からのリアルタイム更新 (2)
● Chime SDK Messaging も CONTROL という message type がある○ 配信単価が通常の message より安価に設定されていて同様の制御向け○ ただし制約が強く、IVS metadata のサイズ上限 (1 KB) より厳しい (30 bytes)■ RubyKaigi Takeout では利用せず、通常の message type で配信した■ もちろんフロントエンドで特別扱いしてユーザーからは不可視© 2022 Cookpad Inc. 29IVS と Chime SDK からのリアルタイム更新 (3)
● IVS metadata のサイズ上限はデータ分割で回避した○ JSON Array に順番に送信する必要のある差分を詰めていって、溢れたら分割○ rate limit のため分割により全体の送信完了までのレイテンシは長くなるが許容© 2022 Cookpad Inc. 30IVS と Chime SDK からのリアルタイム更新 (4)
● チャットに関するデータもリクエスト数を削減したい● チャットの発言者には名前の他に下記のようなデータがある○ 発言者のロール (Ruby コアコミッター、スピーカー)○ 登壇中かどうか (さらにハイライトさせたい)○ アイコンのバージョン (更新時に cache を飛ばすため, cache buster)● しかし別途の API リクエストに頼ると thundering herd 状態になってしまう● Chime SDK Messaging から配信されるデータに含みたい○ AppInstanceUser の Name 属性にエンコードして埋め込んだ○ 長さ制約の都合、JSONではなく専用の簡易フォーマットを用意○ Metadata は AppInstanceUser の管理系 API でしか意味がないので使えず● なお、登壇中スピーカーのハイライトは時系列によって異なるため別で差分対応で配信© 2022 Cookpad Inc. 31チャット発言者の属性データ埋め込み
© 2022 Cookpad Inc. 32結果参加者 900 人程度で、CloudFront には 200rps くらい、バックエンドには 5~10rps くらいとなった
配信映像の作成と送出© 2022 Cookpad Inc. 33
● 配信に携わるスタッフは物理的に集合して運用していた○ 頑張れば完全リモートもできなくはないが、余力がない● 登壇は「事前に録画して提出してもらった mp4」「Zoom によるリモート登壇」のどちらか。○ リアルタイム登壇は Zoom Rooms の NDI 出力 (比較的最近の機能) を元に画面を作成して MediaLive へ送出© 2022 Cookpad Inc. 34映像配信あれこれ: 配信会場
● RubyKaigi では日本語→英語の同時通訳を手配○ 逆はない (みんな英語を聞けてね)○ 通訳も Zoom の通訳機能でリモート参加● 配信は「同じ映像 + 音声は通訳」のものを用意○ ユーザーが通訳オプションを有効にすると接続先が切り替わるように● リアルタイムの通訳は最大で 1 並列○ 2 トラック編成だったが、Track A と B で同時に通訳が必要にならないようにした○ 通訳配信の構成や通訳側のオペレーションの負荷を下げるため、通訳配信は 2 トラックで共用した● 実体としては Track A, Track B, 通訳版の 3 配信。Zoom Meeting は 2 つ© 2022 Cookpad Inc. 35通訳
● takeout-app で通訳配信 URL はトラックごとに設定できるようにしてある○ そこに同じ URL を設定した (しても問題ならないようにした)● 通訳配信のオンライン状態をメインの配信とは独立して設定できるように○ トラック間でオン・オフ状態を入れ替えて共用をシンプルに実現● takeout-app の実装としては共用されている事自体は意識する必要がなくなった© 2022 Cookpad Inc. 36通訳 (2)
通訳なし通訳あり通訳あり通訳なし● ユーザー操作によらない接続先 (配信URL)の切り替えは最小限にしたい● 下記フラグで管理○ セッションに通訳があるか○ トラックの通訳配信はオンラインか○ ユーザーが通訳オプションを選択しているか● セッションに通訳があるかどうかはオプションを画面に出すかどうかにだけ寄与する○ オプションを隠しても無効にはしない○ 右の例だと A の (2) 中は通訳ボタンは非表示、でも(1)で有効にしていれば通訳配信へ接続したままになる○ そして (4) で初めてメイン配信に切り替わる© 2022 Cookpad Inc. 37通訳配信とメイン配信の接続切替を最適化https://github.com/ruby-no-kai/takeout-app/blob/25d09cd46cb87a8d42538e1fdb084518aa20aaad/app/javascript/TrackVideo.tsx#L202Track A Track B通訳あり 通訳なし通訳なし通訳なしここで通訳配信をBへ付け替え配信内容もBへ変更する(1)(2)(3)(4)通訳配信メイン配信
● 2021/4 に MediaLive に Motion graphics overlay という機能が入った○ 任意の html を表示できる。OBS の Browser Source のようなもの● 配信ソース間を切り替える時にトランジションのエフェクトを作れるのではないかと試行錯誤● 出来て、かつ運用もしたが難あり。○ あくまでも情報を表示することに留めたほうがよさそう○ Motion graphics を表示したまま Input Switch すると一瞬 overlay が非表示になってしまう。○ フレームレートが安定しない© 2022 Cookpad Inc. 38Motion Graphics によるトランジション
© 2022 Cookpad Inc. 39Motion Graphics + Input Switch の workaroundMotion Graphics Overlay で背後のInput が不可視になった時、一瞬静止画の Overlay を挟んで Input Switch
● セッションとセッションの間の幕間で表示する画面○ スポンサーのロゴや次のセッションの情報などを表示する必要があった● 画面自体は takeout-app に React で Web ページとして実装● Motion Graphics は前述のトランジションに利用しているため利用できない● OBS browser source で出した映像を MediaLive に入れておくことに○ 複数の MediaLive Channel に同じ映像を Input するのをサボりたい…。○ OBS から IVS に配信して MediaLive の HLS Input を利用したが失敗© 2022 Cookpad Inc. 40幕間映像
● 英語セッションはそのまま、日本語セッションは通訳音声から字幕を生成する● Chime SDK Messaging 上の字幕専用チャンネルへ字幕を表示したユーザーを joinさせて字幕用の UI で表示© 2022 Cookpad Inc. 41字幕の配信
● 字幕データの作成は以下のような流れ○ MediaLive から UDP output で VPC へ音声のみ送信○ Amazon EC2 インスタンスで ffmpeg で受信 & コンテナと音声フォーマットを変換○ Ruby スクリプトで Transcribe へ送信して得られたデータを Chime SDK へリレー● ffmpeg -i udp://0.0.0.0:10000 -f mpegts-c:a pcm_s16le -vn -f s16le -ar 16000 -ac 1 - | ruby serve.rb …● 1 台の t4g.micro で 2 トラック分処理していたがまったく問題なかった© 2022 Cookpad Inc. 42字幕の配信 (2)
● MediaLive, IVS ともに Closed Captioning として EIA-608 (Embedded) をサポートしているので、本来はこちらに乗せるのがベスト○ もともとテレビ放送の規格で複雑なのと、プレイヤー側の実装など考慮することが多くRubyKaigi Takeout 2021 では断念● また、いくつか単語を Transcribe に語彙登録したら精度が上がって良かった○ テクニカルやドメイン固有の単語が多いので、業者依頼より精度が高いシーンはあったかもしれない© 2022 Cookpad Inc. 43字幕の配信 (3)https://github.com/ruby-no-kai/takeout-app/blob/master/caption/rk2021_words.txt
● takeout-app 自体は問題なく運用できた○ いくつかバグはあり会期中修正に追われたものの、パフォーマンス面は万全に対策したことで問題なし● MediaLive Channel の運用で大きな事故は起こしてしまった○ 管理機能を UI として実装するのが間に合わず、スクリプトや手動操作による事故が誘発された● 次回以降は改善を予定© 2022 Cookpad Inc. 44ふりかえり
● https://rubykaigi.org/2022/○ 2022/9/8 - 10○ 三重県 & バーチャルのハイブリッド開催● 最新情報は Twitter @RubyKaigi をフォローしてください© 2022 Cookpad Inc. 45RubyKaigi 2022
● RubyKaigi チームでは Ruby や Ruby コミュニティが好きな人を募集しています● なんか公式サイトを見ると強そうな人がたまたまたくさんいるけど大丈夫!● 興味あればおこえがけください© 2022 Cookpad Inc. 46RubyKaigi 2022: スタッフ募集中?
● ここまで何故スライドが Cookpad なのか思っている人もいるはず…● 登壇者 (sorah) の所属企業である Cookpad についてここで唐突に言及します○ sorah は業務の一部で RubyKaigi などコミュニティ活動をやっています○ また、弊社は Ruby コミュニティや Ruby を積極的に応援しています。full-time のRuby コアコミッターも在籍!● 本日紹介した takeout-app は sorah の業務経験が大きく活きています。○ 最新の技術やサービスを活かして一緒にサービスやインフラの開発をしませんか? 同じような課題や経験は日々の業務で活きます● https://cookpad.jobs または sorah まで気軽にお声がけください© 2022 Cookpad Inc. 47Cookpad: We’re hiring
● RubyKaigi Takeout 2021 は AWS 各種サービスを駆使して、14 日でバーチャル会場を構築し無事に開催しました● RubyKaigi 2022 もやります● https://github.com/ruby-no-kai/takeout-app● Cookpad も絶賛求人中です○ takeout-app は sorah の業務経験が大きく活きています。最新の技術やサービスを活かして一緒にサービスやインフラの開発をしませんか?○ https://cookpad.jobs© 2022 Cookpad Inc. 48まとめ