グノシーのアクセスログ解析基盤

茂木大夢氏(以下、茂木):「グノシーのアクセスログ解析基盤」というタイトルで発表させていただきます、茂木と申します。mgi166という名前でやっています。よろしくお願いします。

まず簡単に自己紹介なんですが、株式会社グノシーの開発・運用推進部というところで働いています。元Railsエンジニアで、今はどちらかと言うとインフラ寄りというか、AWS周りなどの担当をしています。

グノシーって、「グノシー」だけじゃなくて「ニュースパス」や「LUCRA」など、いくつかサービスがあるんですが、私は「グノシー」本体の担当がメインとなっております。

本日の内容なんですけど、グノシーのログ周りを中心としたインフラアーキテクチャの事例ということで、紹介します。

ログ周りと言うと、まず最初に考えるのは「ログを集める」ということだと思います。そこについてまず簡単に、どんなことを考えているか紹介しようと思います。

そもそも僕らはなぜログを集めているのかというところです。各社、特性で出てくるところだと思いますが。例えばこんな理由があるかなと思っています。

実施した施策の反応を見るために、僕らはログを集めます。なんでかと言うと、その施策を打ったことによって、ユーザーさんがどういう反応をしたのか知りたいからですね。これは1つあるかなと思います。

あとは、プロダクトをよりブラッシュアップするため、というのもあるかなと思います。例えばグノシーだと、ログをインプットに機械学習で作ったモデルをどんどん強くしていく、みたいなところもあります。例えばそういったところにログが使われます。

あと、僕らはエンジニアなので、エラーがあったときの原因調査のためにログは残しておきたい、集めておきたいというところも理由としてはあります。やはりログがないと僕らは原因を追えないし、場合によっては、ログに流れるメッセージのキーワードをトリガーにして、アラートを発生させたいとか。異常に気付きたいというときに、ログが必要なこともあります。

あとは、怖い人に詰められたときに、証拠となる記録を出すため。怖い人っていろいろいると思うんですけれども、例えば自分の上司かもしれないし、あるいはすごく堅い、法的ななにかの人から「これどうなってるやんけ」と言われたときに「いやいやうちはこういう感じでちゃんとログを取っていて、悪さした人はいません」みたいな証拠を出すことができます。そういう理由でログを集める、みたいな側面もあると思います。

あと、これは少し特殊かもしれませんが、ログを貯めることが顧客に提供する価値である場合があります。そんなサービスを提供してる場合ですね。ざっと思い浮かんだ場合だと、例えばPapertrailとか、あとはmackerelさんとかそうかもしれません。ああしたサービスを入れて、ログを集めて、それを可視化して、それが価値になる……みたいなところもあるかなと思います。

ログを収集する2つの目的

前置き長くなってしましましたが、今回話すのはこの2つです。「実施した施策の反応を見るためにログを集める」アーキテクチャ。あとは「プロダクトをよりブラッシュアップする」アーキテクチャ。この2つを説明しようかなと思っています。

この2つですが、端的にどういうことかと言うと、ログを集めて活用しているなかで、上の部分は、いわゆる分析の用途で活用するということであると考えています。そして下の部分はプロダクトを改善する用途で活用する。この2つであると考えているので、それぞれ2つのサブテーマについて見ていきたいと思います。

最初に分析用途ですね。こちらはグノシーのバックエンドのすごく雑な概要図なんですけれども。

ユーザーは主にアプリから来るんですが、アプリの人はAPIサーバーの裏側を通して、データ置き場にログが流れるんですね。S3とか、あとはElasticsearchサービスなんですけれども、そのあたりのログが最終的に流れます。

そして、APIサーバーは後ろの、RDS、ElasticCache、Dynamoなどを見ているんですが、そのあたりからデータを返す。そして上に貯まったログが、機械学習やLambdaなどで使われるソースになっていて、いろいろごにょごにょして、いい感じになったデータをDynamoやRDSにつっこみなおす。それをAPIサーバが参照して、例えば記事が更新されたり、みなさんの興味のある情報が見れるようになる、といった感じの構造になっています。

分析に使うのは、主にここの部分です。ここについて話をしていきます。

Gunosyにおけるログの流れ

とはいえそんなに特別なことはやってないません。まずはログがどう流れているかお話しします。先ほども説明したとおり、ユーザーさんのクライアントのアプリがあって、APIサーバーを立てているんですが、そこにFluentdがいて、それがS3とBigQueryにログを流します。

そこからさらにDB、RedshiftやAthena、これはS3なんですが、prestoなどにデータが移動して、それをRe:dashのほうから統合的に見る、みたいな感じになっています。

そして、このS3から次のDBのところなんですが、ETLはただのバッチなんですが、バッチを使って移動しています。

「バッチとはなんぞや」という話なんですが、この図で言うところの、左から2番目の列ですね。生ログがあって、そこからバッチが定期的に動いて、すこし古臭いんですがRedshiftに投入できるようなログにして投入しています。

一方で、同時並行でECSでdigdagを動かし、RDSにあるユーザーさんの情報なども取って来て、全部S3にぶち込んでいます。そして、S3に投入したものはprestoで見ることができますし、Redshiftに投入したものはRedshiftにあるままRe:dashから見れる、みたいな感じです。

Re:dashなんですけれども……ごめんなさい、たくさんグラフがあるんですがちょっと見せられなくて。毎日朝会で確認しています。左のほうにあるんですが、DAUや、あとは動画配信もやっているので、そこらへんの情報だったり。あとはプッシュの開封率など、いろいろ見ています。

一旦ここまでのまとめです。一次ログ置き場は、基本的にS3とBigQueryにぶち込みます。そして、必要に応じてDBにロードして、それをRe:dashで見る。Re:dashで見るDBのことをデータソースと言うんですが、そのデータソースに投入してRe:dashで見ています。そして、可視化したRe:dashのグラフは、毎日朝会で共有している、という感じですね。ここはわりと普通かなと思っています。

改善に用いる「ユーザー行動のログ」

もう一方の、プロダクト改善用途について話をしようかなと思います。

そもそもプロダクト改善用途にどんなログが使われるのかという話なんです。ひと言で言うと「ユーザーの行動のログ」です。記事のクリックのログや、広告のインプレッションのログなど、そういうものが主になります。それ以外にもいろいろ参照してるんですが、主にこの2つかなと思っています。

それがどのように使われるのかと言うと、端的に言うと「ユーザーに最適な情報を届けるため」に活かされます。ユーザー一人ひとりに対して、興味のある記事を出すため。あるいはプッシュ通知。開いてくれそうな、知りたそうな情報をいち早く届けるために使われています。

それがこの概要図なんですけれども、1番左側、先ほど言ったクライアントですね。

ユーザーさんの端末があって、それがAPIサーバに行っています。そして、上のほうの図は先ほどとも重複しますがS3に流れていっています。

一方で、一部のログはクライアントから直接Kinesis Streamにがしがしリクエストを投げていて、クリックのログを流していきます。先に上のほうから説明しますが、生のログなど、その他のいろいろな情報がS3にアップロードされるので、それをEMRやECS上のなにか、バッチだったりそういうのに動いて、マル秘のベクトルを生成します。

そして、下のほうの図なんです。下は、ユーザーのクリックのログなどが即座にKinesis Streamに流れて、それからLambdaが起動して、これもいい感じにいいことをやって。これはユーザーのベクトルなんですが、ユーザーがどういうところに興味を持ってるのか、みたいなところのユーザーベクトルが作られます。

という感じで、そこらへんに貯まったDB、DynamoだったりS3などを、APIサーバからリクエストが来たときに取って来て、それでレスポンスを返す、みたいな感じになっています。

詳しくはテックブログにも書いてあるので、見てもらえたらなと思っています。

記事情報のスコアリング

そして、1番最初に説明するのはこの上側のほうです。記事の情報をスコアリングする部分について話をしようと思います。

先ほども説明しましたが、digdagのバッチはユーザーのデータを取って来ているので、RDSからいろいろとデータを引っこ抜いてきて、一旦S3に上げる、みたいなことをやっています。そこからさらに、S3からEMR、あるいはECS。これはAirflowなんですけれども、これが動いてマル秘のベクトルを生成する、みたいな感じになっています。

これは全部、定期的にバッチで行われていて、そのバッチのスケジューリングはすべてAirflowやdigdagが持っている、という感じですね。

次に、下側です。ユーザー属性の更新のほうなんですが、こちらについて説明しようと思います。

こちらは先ほども言ったとおり、ほぼリアルタイムでユーザーベクトルを更新するという仕組みになっています。どうなっているのかというと、1番最初にクリックのログがあって、それでLambdaが起動して、わりと新しめなログを突っ込んで、いい感じにベクタライズする、みたいな感じになっています。

下のほうはクローラーから来る記事のデータなんですが、いわゆるメディアさんから送られる記事などをたくさんクロールして、その記事をベクトル化します。それをDynamoにぶち込んでいて、それらを掛け合わせて「ユーザーがどんな記事に興味があるのか」みたいなところの情報を取って来るようになっています。

1番後ろのマル秘のベクトルなどが作られますよ、というところです。作られたからAPIサーバは、それを参照して返すことができるようになっています。

ここまでのまとめですが、ユーザーの行動ログをもとにプロダクトの改善を裏側の仕組みを使って行っています。とくにユーザーのクリックのログからユーザーのベクトル更新は、ほぼリアルタイムで行っています。

一部のスコアリングや評価はリアルタイムでは行っていなくて、バッチで対応しています。これらはdigdagとかECSで動いている、という感じですね。

AWSの仕様に引っ張られる部分も

まとめです。運用していて思うところなんですが、良くも悪くもグノシーはAWSにどっぷり浸かっています。フルマネージドで、初期導入や運用コストはすごく低いんですけれども、一方でAWSの仕様に引っ張られるところはけっこうあって。便利に思う反面、ちょっと苦しむところもあったりします。

分析用途のログなどは……実はDBとか、1つのシンボルで今は表現したんですけれども、本当にいろいろなところに散らばっていて。けっこうカオスなことになっていて、「これは今も使ってんだっけ?」みたいなところとか。あるいは実はほとんど使ってなくて、簡単に移行できて「これは消せるんじゃないか?」みたいなところは、いくつかあったりします。

あとは分析用途で使う、とくにログのスキーマ管理については、非常に悩ましいなと思っていて。S3などはべつにいいんですが、BigQueryとかはスキーマがあるから、それをあるときから更新したりすると、そこから過去のログを参照できなくなったり します。このへんもすごく悩ましいなと思っています。

今のところ、グノシーではそれをjsonでまるっと保存して、必要に応じてBigQueryなどのDBに1回吐き出したものを、もう1回べつのテーブルに吐き出して、そこでもう1度分析する、みたいなことをやっています。これは変更のコストが高いことを意味しているので、本当に悩ましいな、という感じです。なのでぜひ、みなさんのところで「こういう方法あるよ」ということがあれば、教えていただいなと思っています。

あとは分析のクエリだったりRe:dashなど、ほぼ自由に触れるんですが、一部でパーティションを指定せずに、ときどきフルスキャンクエリが発生して「うわぁ……」ってなることもどうしても発生してしまっていて。これは本当に、マネー的な意味でけっこう痛いんですが、とはいえ「やらかしたからその人のアクセス権奪う」みたいなことはちょっと違う気がするなぁ、というところで。このへんもみなさん、どうやって対策してるのか気になるところですね。

最後に、グノシーで扱っているログ周りの基盤について、「分析用途」「プロダクト改善用途」に分けて、それぞれご紹介いたしました。

分析用途はわりとセオリー通りの構成かなと思っていて、S3がメインなんですが、そこに1回データをぶち込んで、それを中間データストレージに移行して、それからRe:dashへ、みたいな感じにしています。そして主なKPIはRe:dashなどでグラフ化しています。

プロダクト改善用途では、リアルタイムなログの取得でベクトルを更新したり。あるいはバッチで更新したりしています。これらはすべてAWSに乗ってるので、AWSに大きく助けられている、という感じです。

以上となります。ご清聴ありがとうございました。

(会場拍手)

digdagとAirflowの使い分け

司会者:ありがとうございました。ご質問ある方、いらっしゃいますか?

(会場挙手)

質問者1:ワークフローのところで、digdagとAirflowがそれぞれあったと思うんですけど、それの使い分けはどうされてますか?

茂木:はdigdagは、Airflow側で使うデータを作るところにフォーカスしていて。Airflowはそこのデータを使って、例えば重要なクエリを叩くためだったり、あるいは機械学習で使うデータを作るために使っています。

質問者1:ありがとうございました。

(会場挙手)

質問者2:自分はわりとGCP使っていて。ログは全部、一旦Stackdriverにぶち込めばいいかなと思ってるんですけど。AWSだとわりと、S3に入れるのが普通という感じなんですかね。

茂木:だと思っていますね。理由としては、どこからでも参照できる無限のストレージみたいなものなので。使い勝手は非常にいいですね。ログが例えば、ディスク溢れて喪失しちゃった、みたいなこともないですし。それを対処するのも充分容易だと思ってるので、そういう意味ではすごく使いやすいかなと思ってます。

質問者2:ログが置かれた瞬間、Lambdaを発火させてもぜんぜんできる?

茂木:できます。

質問者2:ならぜんぜん便利だよね、みたいな感じ。

茂木:はい、それもありますね。

質問者2:ありがとうございます。

司会者2:それではありがとうございました。

(会場拍手)