LINE NEWS、2013年からの歩み

稲葉大樹氏:みなさんこんにちは。LINEの稲葉と申します。本日は「Technologies That Support The Distribution of LINE NEWS」と題して、LINE NEWSの記事配信、とくにその中でもパーソナライズされたレコメンドの配信に関する話をしていきたいと思います。

ちなみに、今日お越しいただいているみなさんの中で「LINE NEWSをふだんから使っているよ」という方はどれぐらいいらっしゃいますかね?

(会場挙手)

半々ぐらいですかね。まだ使ったことがないみなさんは、ぜひこのあとLINE NEWSを使い始めていただければと思います。

本日のアジェンダに入る前に、軽く自己紹介をさせていただきたいと思います。自分は今、LINEの新卒入社2年目で、ふだんはLINEのサーバサイドの開発を担当している者です。

本日のアジェンダはこんな感じになっています。まず、LINE NEWSをこのような大々的な場所で発表させていただくのは初めてなので、まずはLINE NEWSについて軽く紹介をさせていただきたいと思います。サービスの内容や規模感をザックリ話したいと思っています。LINE NEWSについてちょっと詳しくなっていただいたあとは、本題であるレコメンド配信についてお話していきたいと思います。

それではまず「Overview of LINE NEWS」ということで、LINE NEWSの紹介をしていきたいと思います。

LINE NEWSは2013年にWebネイティブアプリとしてリリースされました。実は今年で7年目の、弊社の中でもわりと古株のプロジェクトだったりします。そして、2017年にLINEアプリの中にニュースタブとして組み込まれました。

LINE NEWSと聞いてみなさんが思い浮かべるのは、どちらかというとこちらのほうが多いんじゃないですかね。そして今に至るというわけですね。他にも外部のメディア各社様との連携を開始したり、LINE NEWS的には大きなイベントもいくつかあったりするんですが、みなさんはそこを深掘りされても困ると思うので、本日は割愛します。

さて、2013年から今日までわりと順調にサービスを拡大し続けてきたLINE NEWSですが、実はニュース以外にもいろいろなコンテンツを配信しています。天気や運行情報などみなさんの生活の役に立つ情報だったり、国民保護情報や避難情報、地震速報などのみなさんの身を守るための情報。サッカーや野球の実況配信などもやっていたりします。

運行情報は自分がよく使う路線を登録しておくと、ニュースタブ上で遅延情報などが見れたりしてけっこう便利なので、まだ使ったことがない人はぜひ使ってみてください。

トラフィックやインフラ構成

そんなLINE NEWSですが、現在どれぐらいのユーザに利用していただいているのかと言いますと、月間6,800万アクティブユーザ、120億PVと、ありがたいことに非常に多くのユーザに利用していただいています。

これがトラフィックとしてはどのような数字として表れるのかと言いますと、デイリーのリクエスト数がだいたい170億、秒間のリクエスト数は1日のピーク時でだいたい37万5,000、アベレージで20万といった感じになっています。ただ、これは自分が適当に選んだ平日の数字なので、大きなニュースがあったりした日などは、もう少し大きくなります。

ちなみに1日のトラフィックの推移を見てみると、こんな感じになっています。12時や20時に跳ねているのを見ると、みなさん昼休憩の間や仕事帰りの電車の合間に見ていただいているのが想像できて、けっこうおもしろいですよね。

そんな感じでニュースアプリとしてはそれなりのトラフィックが来ているわけなのですが、それを捌いているインフラはこんな感じになっています。

アプリケーションサーバとしてはAmon2というPerl製のフレームワークで動いているサーバが44台、お馴染みのSpring Bootで動いているサーバが30台といった感じになっています。

今「え? Perl?」と思った方、絶対にいらっしゃいますよね。そうなんです。LINE NEWSでは今も現役でPerlが動いていたりします。この辺は完全に歴史的なあれですね。徐々にJavaへの移行は進めていて、本日話すレコメンド配信のシステムは全部Spring Bootのサーバの上に実装されています。

DBサーバとしてはMySQLが用途別に3台、MongoDBが21台。キャッシュサーバとしてはmemcachedのサーバが44台。RedisはSentinel構成のものが3台、Cluster構成のものが1台といった感じになっています。memcachedがPerl用、RedisがJava用といった感じで使い分けられています。

また、他にもバッチサーバやRSS、SFTP、SOAPの外部連携サーバ、CMSサーバなど、いろいろなサーバがあります。これらのインフラの上でLINE NEWSではRSSやSFTP、SOAP経由の外部データのインポート処理、LINE NEWS独自の記事本文フォーマットのパース処理、LINE公式アカウントのメッセージ配信など、他にもいろいろな機能を提供しています。

これらについてすべて詳しく説明していると本日の40分ではとても収まりきらないので、本日はその中でもとくに技術的におもしろそうなパーソナライズされたレコメンドの配信に焦点を当ててお話しさせていただこうというわけですね。

パーソナライズされたレコメンド機能

というわけでLINE NEWSの紹介はこのあたりにして、ここからはLINE NEWSがどのようにしてユーザにレコメンドをお届けしているのかという話に入っていきたいと思います。

LINE NEWSでは「国内最大の記事データ、ユーザデータに基づくレコメンドによってLINE NEWSを自分がほしい情報が詰まっているものにする」というミッションのもと、ユーザ一人ひとりにパーソナライズされたレコメンドを提供しています。

ユーザのみなさんに最も見ていただいているであろう、ニュースのタブを開いたときのトップ画面にもレコメンドが導入されています。画像でいうと一番左の部分ですね。

LINE NEWSのレコメンドはマシンラーニングによるレコメンドだけでなく、運営チームによる手動のレコメンドが行われています。ユーザにはこの2種類のレコメンドが混ざった状態で表示されています。

マシンラーニングで自動化されたレコメンドにわざわざ手動レコメンドを導入しているのは本末転倒のように見えるかもしれませんが、ここには「より一層ユーザの興味に沿った記事をお届けしたい」というLINE NEWSの熱い思いがあったりします。

ただ、みなさん。手動レコメンドと聞いてもどんなものかあまりイメージがわかないですよね。マシンラーニングのレコメンドと合わせて、もう少し詳しく説明していきたいと思います。

まず、マシンラーニングによるレコメンドですが、これはレコメンドの生成はLINE NEWSで行っているわけではなくて、Data Labsと呼ばれる社内のマシンラーニングチームによって生成されたものを取り込むかたちで動いています。

レコメンドは複数に分割されたファイルとして提供され、全部で1億人を超えるユーザ分のレコメンドが格納されています。1億というとLINE NEWSのMAUよりだいぶ多いですが、レコメンド自体はLINE NEWSではなくLINEの国内ユーザ数分が生成されているため、このような数字になっています。初めてニュースタブを開くユーザに対して何も表示しないというわけにはいかないので、このようなかたちになっています。

レコメンドにはユーザ1人につき200件の記事IDが入っています。なので合計すると1億×200で、200億件の記事IDが入っている感じですね。このファイルが毎時間更新されるので、LINE NEWSは毎時間に200億件の記事IDをインポートする必要があります。

対して手動レコメンドですが、こちらはLINE NEWSの運用チームがCMS上で設定を行うものです。レコメンド対象の指定は年齢や性別、都道府県レベルの居住地域などその他さまざまな属性の組み合わせによって行われています。

例えば20代の男性で東京・神奈川に住んでいる人にはこの記事を表示するといった感じの使い方をされます。どの媒体をフォローしているのかという情報も指定できるので、例えばスポーツ系の媒体をフォローしている人には野球のニュースを出すといった使われ方もされます。

レコメンドは並行して何件も設定することが可能で、また、一つひとつに表示期間を設定することが可能です。ユーザには設定されたレコメンドの中から表示対象、かつ表示期間中のものだけがマシンラーニングによるレコメンドの中に混ざって表示されます。また、この際にマシンラーニングのレコメンドの中のどの位置に混ぜて表示するのかもCMS上から設定することができます。

マシンラーニング+手動レコメンドになった背景

この2種類のレコメンドですが、初めからマシンラーニングと手動レコメンドのハイブリッドだったわけではなくて、当初はマシンラーニングによるレコメンドだけが行われていました。そこにあとから手動レコメンドが導入されたわけなんですが、初期のシステム構成や実装に問題があり、それを解決して現在の構成へと至っています。そこについて順を追って紹介していきたいと思います。

まずはマシンラーニングによるレコメンドだけを行っていた時代の話をしたいと思います。レコメンド配信の処理については大きく分けてリクエストの処理とインポートの処理があるのですが、まずはリクエストの処理についてお話していきたいと思います。

レコメンドが導入される前のLINE NEWSのリクエストのプロセスは、ほとんどがこんな感じになっていました。ページを高速に表示するためにCDNをかなり活用していました。記事のページなどは当然ユーザによって内容が変わるものではないので、そういったものはどんどん積極的にCDNに入れるキャッシュを利用していました。

ここにレコメンドが導入されると、当然リクエストには何らかのユーザを識別できるパラメータを乗せる必要が出てきます。サーバはそのパラメータに応じてレスポンスを返さなければならないので、CDNによるキャッシュを利用することができなくなってしまいます。

そのため、リクエストが来るたびにOrigin側で処理を行わなければならなくなるわけですが、これに対してLINE NEWSではどのように対処したのかという事例を紹介していきたいと思います。

先にアーキテクチャの全容をお見せしておきます。イベントの流れに沿ってこれをご紹介していきたいと思います。

ここに関してはあとでもう少し詳しく説明させていただきますが、マシンラーニングチームによって生成されたレコメンドをRedisクラスタ上に事前にインポートしておきます。

実際にユーザからリクエストが来ると、まずはRedisクラスタからそのユーザに対するレコメンド記事のリストを取得します。レコメンド記事のリストはデータ的には記事IDのセットになっています。

レコメンド記事リストの取得に成功すると、記事の情報をキャッシュしているRedisSentinelにMGETのオペレーションを投げます。MGETはGETのキーを複数渡せるバージョンという感じのコマンドです。非常に便利なオペレーションなんですが、クラスタ上では使えないというデメリットがあります。

そして、キャッシュがヒットしなかった記事の情報のみ、MySQLから取得しています。

MySQLから取得した記事の情報はキャッシュサーバにキャッシュをします。こうすることで複数のユーザ間で重複している記事に関しては、一度MySQLから取得すれば次回からはキャッシュがヒットするようになっています。

そしてRedisとMySQLからそれぞれ取得した記事の情報をユーザにレスポンスとして返しています。

実際にMySQLとRedisからそれぞれどれぐらいの記事情報を取得しているのかというと、こんな感じになっています。

グラフは分間のものなんですが、黄色い線がRedis、0にぴったりと張り付いている緑の線がMySQLから、それぞれ記事情報を取得した回数になっています。これだけですでにほとんどキャッシュが使われていることが一目瞭然なんですが、実際に数字を見てみてもピーク時でMySQLが約5,000、Redisが約1,000万といった感じになっています。

ちなみに、ここまで何事もなかったかのように話してきたんですが、実際には記事情報のキャッシュサーバのネットワーク帯域を食い潰してしまいました。それに引きずられて、アプリケーションサーバが次々に落ちていくという大事件を引き起こしてしまったのですが、それはまた別の機会にお話しできればと思います。

そんな話をしたあとに言っても説得力がまったくないんですが、実際のところ、ユーザごとのリクエストを処理すること自体はそこまで難しい問題ではありませんでした。