アジェンダ紹介

藤井力哉氏:それでは始めます。「ABEMA」バックエンドエンジニアの藤井力哉から「コメント機能におけるTwitter連携機能で動画がシェアされる際のGo製サーバー開発」というタイトルで発表いたします。

(スライドを示して)最初に自己紹介をさせてください。私は藤井力哉と言います。2020年京都産業大学を卒業後、株式会社サイバーエージェントへ新卒入社しました。入社後はABEMAへ配属されて、これまでバックエンドエンジニアとしてサービス開発に従事してきました。

(スライドを示して)今回のアジェンダです。まずは、ABEMAのコメント機能について簡単に説明をします。次に、今回Twitterに投稿する動画の切り出しはサーバーサイドで実現したのですが、その手法についてお伝えします。その後、今回のコメント機能を作る際にパフォーマンス向上のためのTipsとしてインメモリキャッシュとsync.Poolを利用したので、それらについてお話しします。

「コメントを見ながらコンテンツを視聴する体験」を提供する「ABEMA」

まずはABEMAで提供しているコメント機能の説明です。(スライドを示して)ABEMAでは、「コメントを見ながらコンテンツを視聴する体験」を提供しています。リアルタイムでのコメントの投稿や参照などが可能です。ABEMAは追っかけ再生という、放送中の番組を任意の時間から再生する機能を提供しているのですが、追っかけ再生中にもその任意の時間に投稿されたコメントを参照できます。

また、Twitter連携というものがあって、Twitterにコメントした内容をツイートすることもできます。ABEMAでは、動画のツイートを許可するかどうかをコンテンツの情報として設定できるのですが、それがONになっていた場合、その任意の時間の動画とともにコメントがツイートされます。

ツイートされる動画は、サーバー側で短く切り出しています。また、この投稿される動画は一応タイミングにも気をつけており、例えば試合でゴールが入った時などのネタバレを防ぐために、そのコメントの視聴位置に基づいて、コメント投稿時のシーンがツイートされた動画の最後のほうに来る設計になっています。

動画切り出しの流れを説明

(スライドを示して)始めに、動画切り出しをどのように実現したかを、簡単なシーケンスを用いて説明します。今回は、一定の間隔で処理が実行されるWorkerというものを作成しました。

コンテンツデータが管理されているデータベースがあるのですが、実行後は、まずそこからコンテンツデータの一覧を取得しに行きます。

取得したコンテンツデータは、動画のシェアが許可されているコンテンツかどうかという設定を持っているので、動画シェアが許可されているコンテンツのみの抽出を行います。抽出したコンテンツの一覧に対しては、(スライドを示して)次のような処理が実行されます。

動画は配信サーバーで管理されているため、配信サーバーから動画のプレイリストを取得しに行きます。その後、動画切り出しをする範囲を決定して、動画のセグメントの取得やセグメントごとの動画作成を行います。このあたりの実装例は後ほどの資料で説明します。

動画の作成が完了したら、作成した動画を特定セグメント分結合させて、完成したらその動画のアップロードを動画データを管理しているデータベースにアップロードします。動画部分の結合部分に関してどのように実現したかも後ほど資料で説明します。

動画付きツイートの流れを説明

(スライドを示して)続いて、動画付きツイートに関して、簡単なシーケンスを用いて流れを説明します。

まずクライアントからサーバーにコメントの投稿のリクエストが来ます。その際にコメントデータを管理しているデータベースにコメントの内容が保存されます。その後ツイートする際に利用する動画データの取得をしに行きます。今回動画データは、インメモリキャッシュでキャッシュする戦略を取りました。

なので、まず動画データをインメモリキャッシュから取得しに行きます。キャッシュから取得できなかった場合は、動画データを管理しているデータベースから取得して、取得に成功した場合はインメモリキャッシュに保存します。こうすることで次回以降、動画データをインメモリキャッシュから取得することが可能になり、データベースの負荷を減らすことでパフォーマンスの向上が見込めます。

動画を取得できたらTwitterが公開しているAPIを利用して動画をアップロードします。ツイートもTwitterが公開しているAPIで行っているのですが、その前にTwitterへアップロードした動画と、ツイートするデータを紐づけるために動画のメタデータを付与しています。動画のメタデータの付与もTwitterが公開しているAPIで行っています。これらの処理が完了したら最後にツイートして処理が完了します。

動画のアップロードやメタデータの付与などはエラーになるケースも考えられるので、その際は動画データを付与せずにテキストだけでツイートするなど、ケアも行っています。

動画の切り出し方法

続いて、先ほどシーケンスで説明した動画切り出しの部分について、Goの実装でどのように実現したかをお話しします。(スライドを示して)今回の動画付きツイートの動画では、HLSを利用しました。HLSはHTTP Live Streamingの略です。動画ストリーミングプロトコルの1つで、Apple社が開発した規格です。

HLSのファイルは、細かく分割した動画コンテンツが格納されているセグメントファイルと、セグメントファイルの再生順や秒数などが定義されているインデックスファイルの2種類のファイルで構成されています。(スライドの)右側には、インデックスファイルの例を記載しています。インデックスファイルにはセグメントの期間情報、読み込むセグメントファイルの順番、セグメントファイルの動画の秒数など、さまざまなデータが定義されています。

次に、今回動画切り出しに使用したライブラリを紹介します。(スライドを示して)今回使用したライブラリは、このライブラリです。こちらのライブラリは、HLSで利用される.m3u8ファイルのパースや生成処理などが可能です。ただしHLSを再生する方法などはサポートされてはいません。今回のTwitter動画切り出しでは、配信サーバーから取得した動画データをセグメントごとに分割するためにこのライブラリを利用しました。

(スライドを示して)この実装は、セグメントファイルを指定してプレイリストを作成する実装です。NewMediaPlaylistという関数を呼び出す際に、sliceをmakeで初期化するのと同じように、事前にセグメントファイル分のキャパシティを用意します。その後NewMediaPlaylistで生成したプレイリストに任意の数のセグメントファイルをアペンドします。

このプログラムを実行すると、(スライドの)右側に表示してあるような結果が得られます。playlist.Encode().String()でm3u8であるインデックスファイルの形式を得られます。これが生成されたプレイリストの結果です。

(スライドを示して)また、今回はffmpegコマンドをGoの実装で実行するアプローチを取りました。ffmpegは、動画ファイルや音声ファイルの再生、変換など、さまざまな操作を行えるコマンドラインインターフェイスです。

今回のTwitter動画シェアの実装では、セグメントごとに区切られたプレイリストをffmpegを利用して連結させました。セグメントごとに区切られたプレイリストは、先ほどお見せした実装で作成したプレイリストです。次のスライドでGoでどのように実現したか、実装例を紹介します。

(スライドを示して)セグメントごとに区切られた動画をffmpegを利用して連結させたGoの実装例がこちらです。argsのところで-iオプションで指定された任意の数の入力ファイルから読み込み、MP4ファイルを作成しました。オプションで渡しているinput.txtはセグメントファイルのファイル名が記載されているものです。

実際の実装では、Goのプログラムでセグメントのファイル名をinput.txtに抽出し、テンプファイルとして書き込みを行って、その結果を利用しました。ffmpegコマンドの実行は、Goの標準パッケージであるexecパッケージを使って行いました。このような実装を行うことで特定のセグメントを連携させたMP4ファイルの動画生成が可能です。

(次回へつづく)