LINE LIVEアプリの設計思想

大澤和宏氏(以下、大澤):「LINE LIVEアプリの設計思想」というタイトルなんですが、私は主にサーバーサイドエンジニアリングをやっているので、サーバーサイドの話を多めにさせていただきます。会場にいらっしゃるみなさんは特にエンコーダやトランスコーディングの話に興味あるかと思いますが、それらは日本では開発していなくて、海外の拠点で開発をしているので、今回は主にクライアントにAPIを提供しているサーバーサイドの技術に関して、15分ほどお話ししたいと思います。

まず自己紹介ですが、大澤といいます。

LINEの開発3センターで、主にLINE LIVEなどの開発をしている部署のマネージャーをしております。

スライドでは「前々回のあらすじ」と書いているんですが、弊社は「LINE DEVELOPER DAY」というイベントを毎年開催してまして、2016年にLINE LIVEのシステムをどう開発しているのかと、システムのアーキテクチャの話をしました。ちょうどそのときの新しい機能としてHLSを提供するサーバーに工夫をして、録画済みのデータを利用してライブ放送を提供する仕組みの話をしました。

これは、あらかじめ用意したビデオファイルをサーバーにアップロードしておき、ライブ放送開始時間を過ぎた後に視聴者がそのファイルへアクセスした時に、HLSを構成するm3u8ファイルをアクセスした時間にあわせて内容に動的に書き換え、そのコンテンツを返す仕組みのサーバーを開発しました。予め指定されたライブ放送の開始時間からm3u8へのアクセス時間との差分を計算してライブ放送時に再生すべきtsファイル名のリストを生成してm3u8のコンテンツとして返すので、例えば視聴開始のタイミングが異なる複数ユーザーが視聴していたとしても、全ユーザーに対して同一のタイミングでは必ず同じ内容の動画を視聴させるような仕組みを作った、といった話をしました。

弊社はCDNを使ってHLSの配信をしているのですが、配信が切断されると「404 Not Found」になってしまいCDNからオリジンサーバーに対する急激なトラフィックがやってきてしまいます。そこで何が起きるかというと、オリジンサーバーはCDNのサーバー群に比べたらだいぶ弱いサーバーなるので、すぐにオリジンサーバーがダウンしてしまってサービスの正常提供が難しくなってしまいます。その場合のフローを、どうやって解決してみたかという話もしました。

あとは、チャットやハートシステムの過負荷対策の話ですね。どんな仕組みでチャットをつくっているのかと、今のバージョンでは違う仕様になってしまっていますが、当時のバージョンでは、視聴画面の右下にあるハートのアイコンを視聴者のかたが無限に連打することがきました。とある配信では2時間の配信で1千万超のハートのインクリメント処理を捌いたこともありました。それをどうやって実装したかを発表させていただきました。

今回は一番上の「LINE LIVEのSystemのOverview」と、チャットシステムがどうなっているかもお話ししたいと思います。

過去の発表の振り返り

前回の発表は2017年の秋でした。

前々回から、サーバーの数が倍ぐらいになっていたり、ランキングシステムが変わっています。視聴者の皆さんからたくさん応援してもらった配信者のランキングシステムを作っていたんですが、Elasticsearchを使って普通にランキングロジックを書いていました。ですが、それだけではElasticsearchが落ちてしまうので、Redisをうまく使ってキャッシュして、システム的に軽くランキングを返すようにしました。

あとは2017年に初めてパソコンを使って一般の方が配信できるようになったんですが、それも既存の仕組みを大きく変えることなく、ちょっとしたキューのシステムをRedisで作ることでパソコンからの配信を可能にしました。

他には、今までLINE LIVEはスタンドアローンのアプリで提供されていたのですが、LINE LIVEを視聴するプレイヤーのネイティブコードがLINEのアプリの中にも含まれるようになって、LINEアプリ上でもLINE LIVEと同じようなUXでライブ配信の視聴できるようになりました。応援アイテムも実装されているんですが、それもLINEのアプリ上で送信できるようになりました。

ここまでが今まで発表してきた内容のあらすじです。

この資料は2016年のときに書いた、今までのサービスの履歴です。LINE LIVEは2014年の2月頃に、LINEの中で動画配信を視聴できる「LINE LIVE CAST」というサービスとしてリリースされたのがきっかけでした。2015年12月に単体のアプリとしてサービスを開始して、かれこれ3年経っています。

前置きが長くなってしまいましたが、今回話す内容としては、3年ちょっと運営してきてテクノロジースタックが変わってきたのでその今昔話と、昔はこういう選択をしたんだけども、どういった理由で新しいミドルウェアやソフトウェアに変更してきたのかについてお話したいと思います。

クライアントサイドの技術スタック

その前に、サーバーサイドの話だけでは物足りないと思ったので、クライアントサイドで現在利用している技術の話もします。

Androidに関しては、次のセッションの人間が一番詳しいので割愛しますが、iOSでは最初はObjective-Cも使って開発していましたが、現在はSwift100パーセントになってます。あとはAPIの通信などはAPIKitを使ったり、WebSocketの通信ではStarscreamを使っています。

あとは、Webも基本的にチャットのシステムがWebSocketを使って提供されています。axiosを使ったりしています。動画再生にはhls.jsを使ってます。

過去のサーバーサイドのコンポーネントなんですが、リリース当時は3つのサーバーのコンポーネントに分けて、チーム開発のメンバーも分けて開発をしていました。

左側がCOREとなるComponentで、クライアントと通信するAPIサーバーのほか、会社全体でMicroservicesとして各種サービスの連携を行う文化があるため、社内の他の開発チームが開発しているサービスからAPIリクエストを受け付けるための社内用APIサーバーなどがあります。

CHATはSpring Bootを使っていて、大量の視聴者からのメッセージをWebSocketを利用して並列的に処理したかったので、AkkaとRedis Pub/Subを使って1個のチャットルームを複数サーバーで負荷分散可能な設計で実装しました。詳細はあとでお話したいと思います。

他には、LINE公式アカウントを運営する企業向けの配信管理画面を作ってました。Springを使ったり、Spring Bootを使ったり、Avansという内製のWebフレームワークを使っていたりするんですが、LINE LIVEの開発初期に集まったメンバーは、それぞれ技術的バックグラウンドが違うエンジニアが集まって開発チームを結成したため、各Componentを担当するエンジニアが作りやすい技術を選択して開発を進めていました。

COREというところは、Memcachedを使ったり、軽量プログラミング言語というか、Perlの文化のエンジニアが多く集まって作っていました。

CMSは昔からSpringを使って開発していたエンジニアの人たちが作っていました。

開発方針としては、全社的にプラットフォーム化して共通して使えるようなサービス、例えば社内にはS3のようにオブジェクトストレージで画像ファイルを保存しておくストレージがあります。そういった社内で他のサービスと共通化できるようなものは専門のチームが開発していて、自分たちがわざわざ作る必要が無いものは既存の社内の仕組みを使って、リリースまでの開発コストを下げて迅速にサービスリリースをする方針で開発をしていました。

先ほども言ったように、動画エンコーダ関連のサーバーは専門のチームで開発されています。

現在のサーバー構成

最近になって、「フレームワークもSpring Bootに統一しましょう」といったかたちで統一しました。これも、同一サービスで複数のフレームワークを利用することは運用コストが高いことと、世間一般的ではない技術を用いてるため新入社員の学習コストが高いので、それらを改善することが目的でした。また、先ほどの古いシステムではJesqueという、Javaで書かれたJob Queueを使っていたんですが、それは社内的にも一般的ではなくあまり使われていませんでした。LINE LIVEをリリースして暫くたった時に、Kafkaを専門的に扱うチームが設立されて、そのチームの担当者が我々のサービスでも使っても良いと言ってくれたので、僕からチームメンバーに「Kafkaを使いましょう」って言って使いだしました。

Memcachedも使われているところも少なくなってきており、RedisがあるならRedisで一貫して保存して利用したほうが運用と保守のコストが減るよね、ということでMemcachedを廃止したり、検索の機能やランキングの機能を新規で追加するときは積極的にElasticsearchを使って開発するようになりました。

あとは、社内のPrivate Cloudのシステムもけっこう最近充実してきたので、そちらに引っ越しています。昔から社内では専門のシステム部門がバーチャルサーバーを提供していて、それを使っていたんですけども、最近は新たに「EC2」のようなPrivate Cloudを開発しているので、そちらに移行する作業も行っています。半年に1回ぐらいは新しいミドルウェアに乗り換えたり、サーバーを引っ越すといったことを延々とやっている感じの開発チームになってきています。

全体のアーキテクチャの更新を長年放置しているといざ問題になった時の改修コストが大きくなってしまうため、要所要所で新しい環境に乗り換えて、システムとして死なない環境を維持できるような開発チームを目指しています。

このスライドは、過去にはこうしたWebフレームワークを使っていて、現在はSpring Bootに変えましたよ、という資料です。

一昨日、JSUG勉強会というSpring Bootの勉強会がありまして、そこで発表した資料を参考として載せてました。

図で見るリポジトリ構成

これは、日本のLINE LIVE開発チームで作っているリポジトリを図にまとめた社内用の資料です。そのまま文字を書いてしまうと、いろいろとよくないものが見えてしまうのでぼかして書きました。この小さい四角が1個のリポジトリです。このくらいのリポジトリ数で開発しています。上の大きい四角がそれぞれiOSとAndroidのクライアントのアプリで、それらの右にある丸い四角がLINEのアプリです。ここの図は「LINEアプリがLINE LIVEのビデオプレイヤーのモジュールに依存してますよ」といったことを書いていて、依存関係もけっこうあります。先程Microservicesアーキテクチャで開発しているとお話しましたが、サーバー関連のリポジトリもLINE LIVEだけで27種類ぐらいあります。

システムの構成はどうなっているかということで、これよりも詳細に書いてある社内用の資料は存在していますが、さすがにそれは外に出せないので、サマライズしました。

COREがAPIサーバーや社内用のAPIサーバーで、CHATサーバーがWebSocketでLINEとかLIVEのアプリにつながっています。COREもAPIでアプリにつながっている感じですね。

社外向けの管理画面(CMS)とかもそれぞれと依存してつながっています。ユーザーに対しておすすめ番組を配信するLINE Botもあるので、それと連携してBot用のサーバーにCOREからリクエストをなげて、配信対象の数だけKafkaにメッセージを書き込んであげて、Kafkaのメッセージを読み込んだConsumerがLINEのMessaging APIを使ってユーザーのみなさまに通知を送っています。それとは別にサービスに露出することが不適切なコンテンツもちゃんとモニタリングしていかなければいけないので、そういったシステムと連携するところも作っていきます。

最近はLINE NEWSの中でLINE LIVEの配信が見れるようになったんですが、それもKafkaを利用して配信開始の通知をLINE NEWS側に送っています。LINE NEWSやその他のサービスが、配信開始通知を受け取り、欲しいコンテンツがあった場合には、LINE NEWS等の管理画面に出してあげるということを自動的にできるようにしました。

なぜKafkaを使いだしたかというと、やはりAPIの設計や、LINE NEWSに提供するためのAPIをLINE LIVEのエンジニアが作るといった部分がサービスをしばらく運用していき、改修が必要になってくると手間になってくる事が予想できたので、そういった密結合することで運用コストが増えそうなところは疎結合で、「あまりコミュニケーションをしなくてもお互い好きなデータを使えるようにしよう」ということでKafkaを使いました。

あとは、図の上の部分は動画配信処理の部分で、LIVEのアプリからMediaServerにRTMPで送ってエンコーディングします。RTMPのパケットを受け取ると、COREのインターナルAPIに通知がいくので配信開始情報をストレージに置いて、MediaServerはRTMPからHLSに変換して、ローカル領域にファイルを置いておきます。

視聴する側はMediaServerに直にアクセスすることなく、CDN経由でMediaServerのHLSのコンテンツを取得します。

先ほど説明を飛ばしたチャットルームについてですが、RedisのPub/Subなどを使うことで複数のチャットのサーバーのインスタンスの中にルームをそれぞれ作って、room2だったら、ClientCで発言した内容は、ClientDでも見ることができます。

ClientBで発言したものはClientAでも見れるようにしたり、Room3の場合は、応援アイテムという有料のアイテムを配信者に送ることができるので、一旦APIサーバーにリクエストを投げて、APIサーバーからチャットのインターナルなAPIサーバーに「応援アイテムが送られたよ」という情報を送信して、その後Redisのストレージに保存して、それをsubscribeしているroom3のクライアントにメッセージが飛びます。Clientがつながっているサーバーは違いますが、送った応援アイテムを「ClientFの人から送られたよ」みたいな感じで表示できるようになっています。

今後やっていきたいこと

監視ツールもいろいろ使ってます。

GrafanaやKibanaはわりと並列で使っていて、それぞれ特色が違うので用途に応じて使いやすいものを使っています。あとはアラート通知では、IMONという自社製のモニタリングツールがあるので、そこで障害が起きたときにメールやメッセージで送るということもしていますし、Prometheus経由でもアラートを投げています。エラーログの数や、リリース後にエラーログが出てないかどうかはKibanaで監視しています。

やっていきたいことも多くて、現在は、本日説明したようにコンポーネントが3つに別れているんですが、分かれていると無駄なこともあるので、一旦コンパクトにまとめてから最適化したいですし、やはりストレージのアクセス、SQLのクエリでもまだ最適化されていないところもあるので運用もちゃんとしたいなと考えています。あとは通信の最適化もしたいですし、配信の遅延などでみなさんお悩みだと思いますが、そういうこともちゃんとしていきたいです。また、採用もやっていきたいなと考えています。

僕からの発表は以上です。ありがとうございました。

(会場拍手)