Slide 1

Slide 1 text

© 2022 Cookpad Inc. RubyKaigi Takeout 2021 バーチャル会場 & 配信の技術的舞台裏 Sorah Fukumori https://sorah.jp/

Slide 2

Slide 2 text

2021/9 に開催した国際会議 RubyKaigi Takeout 2021 のバーチャル会場を 内製した話 ● 内製までの流れ ● 構成の選定 ● 各種工夫 © 2022 Cookpad Inc. 2 Agenda

Slide 3

Slide 3 text

昨年末 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. 3 Agenda

Slide 4

Slide 4 text

● 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. 4 Who am I

Slide 5

Slide 5 text

● https://rubykaigi.org ● プログラミング言語 Ruby に関する世界最大級の国際会議 ○ 日本で開催され、近年は東京でなく日本各地で開催中 ○ 最後の物理開催は RubyKaigi 2019 (福岡) ● 参加者は 1,200 人規模 ● RubyKaigi 2020 は COVID-19 の影響でキャンセルとなりバーチャルへ ○ 無料にして YouTube Live を利用 ○ 従来通りの RubyKaigi と同じ体験ではないことから “RubyKaigi Takeout 2020” として開催 © 2022 Cookpad Inc. 5 RubyKaigi

Slide 6

Slide 6 text

● 2021 年もオフラインでの開催は早期に断念 ● 2020 は緊急避難的に無料かつ YouTube Live で開催したが、2021 は従来通り 有料に戻したい ○ 有料にすると YouTube Live の選択肢がなくなる ● バーチャルカンファレンスのソリューションを探す? ○ RubyKaigi 特有の要件を満たす選択肢を検証する余裕は正直ない ○ フルタイムで誰かが運営している訳じゃないので © 2022 Cookpad Inc. 6 RubyKaigi Takeout 2021

Slide 7

Slide 7 text

● 複数トラック (2+ セッションが並行できる) ● 英語通訳のサポート ○ 日本語 → 英語 の同時通訳がある。逆はない ● 字幕サポート ○ 日本語音声でも英語音声でも 英語字幕のみ 提供 ● 物理的体験の再現 ○ Ruby core team や Speaker の名札があったりしていたので、再現したい ● スポンサーベネフィット ○ 幕間中のロゴ表示や、宣伝テキストの表示を用意したかった ○ バーチャルだけでのスポンサーベネフィットを考えるのはかなり難しい… © 2022 Cookpad Inc. 7 RubyKaigi のバーチャル会場に求められる要件

Slide 8

Slide 8 text

● イベントを準備するのが楽しくてやっている Organizer としては物理開催じ ゃなくなってだいぶ楽しさが減っているなか、バーチャル会場も外から 調達してきたらだいぶ楽しくないな…となった ● 無茶かもしれないけど作っていい? と聞いて作らせてもらうことに ○ 今回はすべて本業の時間にはしなかったのでなかなかしんどかったところはある ○ 累計の作業期間は 14~15 日程度 © 2022 Cookpad Inc. 8 内製への道

Slide 9

Slide 9 text

● 落ちないでほしい ○ しかしオーバープロビジョニングはもったいないしダサい…。 ● バーチャルカンファレンスのトラフィックとか実績がないし何も分からない ○ 信用できるミドルウェアを使う、自前のバックエンドへは出来る限り リクエストをキャッシュ © 2022 Cookpad Inc. 9 目標、というかバーチャルならではの要件

Slide 10

Slide 10 text

● https://github.com/ruby-no-kai/takeout-app ● ライブ映像の再生 ○ 同通バージョン再生のサポート ● チャット ○ 名前・アイコン・ロール設定 ○ 現在のスピーカーの強調表示 ○ モデレーション ○ 「RubyKaigi」名義での発言 ○ 発言のピン止め ● 複数トラック ● 現在のセッション情報の表示 (他トラックも) ● Auto captioning による英語字幕 ● 幕間映像の生成 © 2022 Cookpad Inc. 10 作った: takeout-app

Slide 11

Slide 11 text

© 2022 Cookpad Inc. 11

Slide 12

Slide 12 text

● 前提: とにかく時間がない ○ フルタイムじゃないからね ● 慣れた Rails と AWS で作る ○ 慣れ、コスト面、アカウント・課金の統一、パフォーマンス・セキュリティへの 信頼 ○ 他の選択肢は学習・検証・金銭コスト含めて高いと判断 ■ 完璧じゃなくてもユースケースを満たすので OK。すぐに使えるのは大事 ■ 担当者の慣れというところが大きなファクタだったとは思う © 2022 Cookpad Inc. 12 構成

Slide 13

Slide 13 text

● フロントエンド: 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 構成

Slide 14

Slide 14 text

● Amazon Chime が提供している機能を自分のアプリに組込むことができるの が Chime SDK ○ いくつかに分割されており、Messaging はチャット機能の提供 ○ Chime SDK は Chime の名前を冠しているが、ユーザー管理などは Amazon Chime とは一切 関係なく利用できる ● 選定理由 ○ 最強とは思わないが我々には必要十分な機能 ○ 安い。外部の類似 aaS より価格体系がシンプルかつ最低利用額がないの が良い © 2022 Cookpad Inc. 14 チャット: Chime SDK Messaging

Slide 15

Slide 15 text

● 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

Slide 16

Slide 16 text

● IVS に直接出力せず MediaLive を経由 ○ IVS より前からあるライブ配信や放送用のサービス ○ 放送用ということもあり冗長化されたパイプラインや複数の入出力など様々な機能がある一方、 そのままでは低遅延にはならないなどの違いがある ● 選定理由 ○ 入力切替がしたい ○ 事前に準備した mp4 の再生がしたい ○ 字幕のために(後述)音声出力を別に取得したい ○ Motion Graphics Overlay 機能を使ってみたい (2021/4リリース, 後述) © 2022 Cookpad Inc. 16 動画: AWS Elemental MediaLive

Slide 17

Slide 17 text

● 音声を与えると文字書き起こしをしてくれるサービス ○ ストリーミングでもバッチでもどちらでも対応 ● RubyKaigi はオフライン開催時から英語字幕の提供をしている ○ 現地・アーカイブ動画共に提供。業者へ外注 ○ 日本語セッションは英語通訳の音声から起こしてもらう ○ RubyKaigi Takeout 2021 で自動での実施にトライ ● 選定理由 ○ AWS にあるから (前述の通り) ○ テストしたらすんなり上手くいったので ○ MediaLive との連携もあり AWS 内に留まって処理できて便利 © 2022 Cookpad Inc. 17 字幕: Amazon Transcribe

Slide 18

Slide 18 text

● ご存知 CDN ● バックエンドへの TTFB 短縮やアセットファイルの配信・キャッシュに利用 ○ 今回のバックエンドは us-east-1 にいるため ● 選定理由 ○ AWS にあるから (前述の通り) ■ もう少し機能のある CDN の方が負荷対策(後述)に有利だけど、許容 © 2022 Cookpad Inc. 18 その他: Amazon CloudFront

Slide 19

Slide 19 text

● RubyKaigi なので ● シンプルな Rails アプリケーションでバックエンドを実装 ○ ログイン・配信状態(セッション内容etc)管理、 クライアントへの API token 発行など ● デプロイは他に内製しているアプリケーションと揃えるために Heroku ○ App Runner の VPC 対応が間に合っていれば採用したかもしれない ● API only で残りは React のための HTML を返すだけ © 2022 Cookpad Inc. 19 バックエンド: Rails (実装)

Slide 20

Slide 20 text

● React + react-router + Chakra UI + useSWR ● 素朴な SPA として実装 ● Webpack (+ simpacker) でシンプルにビルドしたものを配信 ○ Rails との連携は HTTP API さえあればいいので Webpacker とか使わない ○ 今なら jsbundling-rails になりそう © 2022 Cookpad Inc. 20 フロントエンド: React (実装)

Slide 21

Slide 21 text

工夫や負荷対策 © 2022 Cookpad Inc. 21

Slide 22

Slide 22 text

● とにかく実績がなくて予測が難しいのでそもそもバックエンドまで届くリク エストを減らしたい ○ リクエストが減るとアプリケーションも高速になって嬉しい! ● CDN でのキャッシュ、ブラウザのキャッシュ、フロントエンドでのキャッシ ュや API リクエスト以外でのデータ配信などで大幅にリクエスト数を減らせ るようにした ○ 現在のセッション情報などを定期的な API リクエストにすると、最大で 1,200 人いるこ とからそこそこの量のトラフィックが来ることになるので考えることが増えてしまう。 これを避けたかった © 2022 Cookpad Inc. 22 負荷対策: 徹底的なリクエスト数の削減をしたい

Slide 23

Slide 23 text

● アセットやユーザーアイコン画像のキャッシュはもちろん、 それに加えいくつかのバックエンドの API をキャッシュ ● 会議進行中に定期的に更新される全ユーザー共通のデータが中心 ○ 各トラックのセッション情報、配信オンライン状況などのデータ ● TTL 短めでキャッシュするようにしている ○ データの freshness は高く維持されてほしいため ○ キャッシュそのものを返してもらえることより、並行する複数のリクエストをまとめる request collapsing の効果に期待 © 2022 Cookpad Inc. 23 CloudFront でのキャッシュ https://github.com/ruby-no-kai/takeout-app/blob/25d09cd46cb87a8d42538e1fdb084518aa20aaad/tf/cloudfront.tf

Slide 24

Slide 24 text

● CDN でキャッシュできるような API に加え、 ブラウザにキャッシュさせた API もある (ユーザー固有) ○ Chime SDK Messaging で利用する AWS credentials ○ Amazon IVS の配信を再生するための JWT ● Cache-Control の state-while-revalidate を組み合わせ、バックグラウンドで 有効期限が切れる前に早めに新しいものを取得するようにするなども © 2022 Cookpad Inc. 24 ブラウザのキャッシュ

Slide 25

Slide 25 text

● https://swr.vercel.app ● React Hook として fetch API などデータ取得ロジックを簡単にラップすることが できるライブラリ。付加機能がめちゃくちゃ強力 ● stale while revalidate の名前を冠する通りキャッシュや非同期 refresh が賢い ○ Cache-Control のそれとはあまり関係がない ○ ウィンドウをアクティブにした時の再取得や定期的な取得などを簡単に実装できる ○ React Hook を良く活かしていて「データ再取得中」の状態をあまり意識しなくてよく、 実装がシンプルになるのがポイント ○ 気付いたら最新のデータでレンダリングが走ってくれる © 2022 Cookpad Inc. 25 useSWR

Slide 26

Slide 26 text

● 既に取得したデータを再度リクエストすることなく、ブラウザローカルで更 新することができる (mutate) ○ たとえば write API を実行して得た差分を、そのリソースの read API から得られている データへマージして、あらためて read API へリクエストせず write した結果を レンダリングさせることができる ○ これを Amazon IVS の metadata 配信などで活用 © 2022 Cookpad Inc. 26 useSWR (2)

Slide 27

Slide 27 text

● Amazon IVS と Chime SDK Messaging で差分を配信 ○ IVS は metadata, Chime SDK はチャットメッセージとして ○ 現在のセッション情報や、最新の閲覧者数、配信のオンライン状況など ● 差分を useSWR の mutate を通して反映 ○ リクエスト数がグッと減る、というか定期リクエストが完全に不要になる ■ しかもリアルタイム性が上がる ○ 差分をマージする実装がなかなか大変 ■ がんばりましょう © 2022 Cookpad Inc. 27 IVS と Chime SDK からのリアルタイム更新

Slide 28

Slide 28 text

● IVS metadata と Chime SDK のメッセージは使い分けていた ● 基本 IVS metadata が一番安く配信できる ○ 配信の HLS segment を活用しているので効率的 ○ 送出している映像より先行することがないのもポイント ● ただし配信映像を再生していないと降ってこない ○ 配信のオンライン状態などは Chime SDK Messaging より送信 ● サイズが膨れる可能性があるデータも Chime SDK を選択 ○ IVS metadata は映像に相乗りする都合、サイズ上限・レートリミットも厳しめ © 2022 Cookpad Inc. 28 IVS と Chime SDK からのリアルタイム更新 (2)

Slide 29

Slide 29 text

● Chime SDK Messaging も CONTROL という message type がある ○ 配信単価が通常の message より安価に設定されていて同様の制御向け ○ ただし制約が強く、IVS metadata のサイズ上限 (1 KB) より厳しい (30 bytes) ■ RubyKaigi Takeout では利用せず、通常の message type で配信した ■ もちろんフロントエンドで特別扱いしてユーザーからは不可視 © 2022 Cookpad Inc. 29 IVS と Chime SDK からのリアルタイム更新 (3)

Slide 30

Slide 30 text

● IVS metadata のサイズ上限はデータ分割で回避した ○ JSON Array に順番に送信する必要のある差分を詰めていって、溢れたら分割 ○ rate limit のため分割により全体の送信完了までのレイテンシは長くなるが許容 © 2022 Cookpad Inc. 30 IVS と Chime SDK からのリアルタイム更新 (4)

Slide 31

Slide 31 text

● チャットに関するデータもリクエスト数を削減したい ● チャットの発言者には名前の他に下記のようなデータがある ○ 発言者のロール (Ruby コアコミッター、スピーカー) ○ 登壇中かどうか (さらにハイライトさせたい) ○ アイコンのバージョン (更新時に cache を飛ばすため, cache buster) ● しかし別途の API リクエストに頼ると thundering herd 状態になってしまう ● Chime SDK Messaging から配信されるデータに含みたい ○ AppInstanceUser の Name 属性にエンコードして埋め込んだ ○ 長さ制約の都合、JSONではなく専用の簡易フォーマットを用意 ○ Metadata は AppInstanceUser の管理系 API でしか意味がないので使えず ● なお、登壇中スピーカーのハイライトは時系列によって異なるため別で差分対応で配信 © 2022 Cookpad Inc. 31 チャット発言者の属性データ埋め込み

Slide 32

Slide 32 text

© 2022 Cookpad Inc. 32 結果 参加者 900 人程度で、CloudFront には 200rps くらい、バックエンドには 5~10rps くらいとなった

Slide 33

Slide 33 text

配信映像の作成と送出 © 2022 Cookpad Inc. 33

Slide 34

Slide 34 text

● 配信に携わるスタッフは物理的に集合して運用していた ○ 頑張れば完全リモートもできなくはないが、余力がない ● 登壇は「事前に録画して提出してもらった mp4」「Zoom によるリモート登 壇」のどちらか。 ○ リアルタイム登壇は Zoom Rooms の NDI 出力 (比較的最近の機能) を元に画面を作成し て MediaLive へ送出 © 2022 Cookpad Inc. 34 映像配信あれこれ: 配信会場

Slide 35

Slide 35 text

● RubyKaigi では日本語→英語の同時通訳を手配 ○ 逆はない (みんな英語を聞けてね) ○ 通訳も Zoom の通訳機能でリモート参加 ● 配信は「同じ映像 + 音声は通訳」のものを用意 ○ ユーザーが通訳オプションを有効にすると接続先が切り替わるように ● リアルタイムの通訳は最大で 1 並列 ○ 2 トラック編成だったが、Track A と B で同時に通訳が必要にならないようにした ○ 通訳配信の構成や通訳側のオペレーションの負荷を下げるため、通訳配信は 2 トラック で共用した ● 実体としては Track A, Track B, 通訳版の 3 配信。Zoom Meeting は 2 つ © 2022 Cookpad Inc. 35 通訳

Slide 36

Slide 36 text

● takeout-app で通訳配信 URL はトラックごとに設定できるようにしてある ○ そこに同じ URL を設定した (しても問題ならないようにした) ● 通訳配信のオンライン状態をメインの配信とは独立して設定できるように ○ トラック間でオン・オフ状態を入れ替えて共用をシンプルに実現 ● takeout-app の実装としては共用されている事自体は意識する必要がなくな った © 2022 Cookpad Inc. 36 通訳 (2)

Slide 37

Slide 37 text

通訳なし 通訳あり 通訳あり 通訳なし ● ユーザー操作によらない接続先 (配信URL)の 切り替えは最小限にしたい ● 下記フラグで管理 ○ セッションに通訳があるか ○ トラックの通訳配信はオンラインか ○ ユーザーが通訳オプションを選択しているか ● セッションに通訳があるかどうかはオプション を画面に出すかどうかにだけ寄与する ○ オプションを隠しても無効にはしない ○ 右の例だと A の (2) 中は通訳ボタンは非表示、でも (1)で有効にしていれば通訳配信へ接続したままにな る ○ そして (4) で初めてメイン配信に切り替わる © 2022 Cookpad Inc. 37 通訳配信とメイン配信の接続切替を最適化 https://github.com/ruby-no-kai/takeout-app/blob/25d09cd46cb87a8d42538e1fdb084518aa20aaad/app/javascript/TrackVideo.tsx#L202 Track A Track B 通訳あり 通訳なし 通訳なし 通訳なし ここで通訳配信をBへ付け替え配信内容もBへ変更する (1) (2) (3) (4) 通訳 配信 メイン 配信

Slide 38

Slide 38 text

● 2021/4 に MediaLive に Motion graphics overlay という機能が入った ○ 任意の html を表示できる。OBS の Browser Source のようなもの ● 配信ソース間を切り替える時にトランジションのエフェクトを作れるのでは ないかと試行錯誤 ● 出来て、かつ運用もしたが難あり。 ○ あくまでも情報を表示することに留めたほうがよさそう ○ Motion graphics を表示したまま Input Switch すると一瞬 overlay が非表示になってし まう。 ○ フレームレートが安定しない © 2022 Cookpad Inc. 38 Motion Graphics によるトランジション

Slide 39

Slide 39 text

© 2022 Cookpad Inc. 39 Motion Graphics + Input Switch の workaround Motion Graphics Overlay で背後の Input が不可視になった時、一瞬静止画 の Overlay を挟んで Input Switch

Slide 40

Slide 40 text

● セッションとセッションの間の幕間で表示する画面 ○ スポンサーのロゴや次のセッションの情報などを表示する必 要があった ● 画面自体は takeout-app に React で Web ページとして 実装 ● Motion Graphics は前述のトランジションに利用している ため利用できない ● OBS browser source で出した映像を MediaLive に入れて おくことに ○ 複数の MediaLive Channel に同じ映像を Input するのをサ ボりたい…。 ○ OBS から IVS に配信して MediaLive の HLS Input を利用し たが失敗 © 2022 Cookpad Inc. 40 幕間映像

Slide 41

Slide 41 text

● 英語セッションはそのまま、日本語セッションは通訳音声から字幕を生成する ● Chime SDK Messaging 上の字幕専用チャンネルへ字幕を表示したユーザーを join させて字幕用の UI で表示 © 2022 Cookpad Inc. 41 字幕の配信

Slide 42

Slide 42 text

● 字幕データの作成は以下のような流れ ○ 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)

Slide 43

Slide 43 text

● 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

Slide 44

Slide 44 text

● takeout-app 自体は問題なく運用できた ○ いくつかバグはあり会期中修正に追われたものの、パフォーマンス面は万全に対策した ことで問題なし ● MediaLive Channel の運用で大きな事故は起こしてしまった ○ 管理機能を UI として実装するのが間に合わず、スクリプトや手動操作による事故が誘 発された ● 次回以降は改善を予定 © 2022 Cookpad Inc. 44 ふりかえり

Slide 45

Slide 45 text

● https://rubykaigi.org/2022/ ○ 2022/9/8 - 10 ○ 三重県 & バーチャルのハイブリッド開催 ● 最新情報は Twitter @RubyKaigi をフォローしてください © 2022 Cookpad Inc. 45 RubyKaigi 2022

Slide 46

Slide 46 text

● RubyKaigi チームでは Ruby や Ruby コミュニティが好きな人を募集していま す ● なんか公式サイトを見ると強そうな人がたまたまたくさんいるけど大丈夫! ● 興味あればおこえがけください © 2022 Cookpad Inc. 46 RubyKaigi 2022: スタッフ募集中?

Slide 47

Slide 47 text

● ここまで何故スライドが Cookpad なのか思っている人もいるはず… ● 登壇者 (sorah) の所属企業である Cookpad についてここで唐突に言及します ○ sorah は業務の一部で RubyKaigi などコミュニティ活動をやっています ○ また、弊社は Ruby コミュニティや Ruby を積極的に応援しています。full-time の Ruby コアコミッターも在籍! ● 本日紹介した takeout-app は sorah の業務経験が大きく活きています。 ○ 最新の技術やサービスを活かして一緒にサービスやインフラの開発をしませんか? 同じ ような課題や経験は日々の業務で活きます ● https://cookpad.jobs または sorah まで気軽にお声がけください © 2022 Cookpad Inc. 47 Cookpad: We’re hiring

Slide 48

Slide 48 text

● 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 まとめ