リクルート『スタディサプリ』のデータ分析基盤を支える技術と活用事例──RECRUIT TECH MEET UP #3
アーカイブ動画
■登壇者プロフィール
株式会社リクルート
プロダクト統括本部 まなびデータプラットフォームグループ
データエンジニア マネージャー 戸井田 明俊氏
新卒でオンラインゲーム会社に入社し、広告事業やデータ基盤のエンジニアを担当。2017年リクルートに中途入社。データエンジニアマネージャーとして、データ基盤の開発・運用やデータプロダクトの開発に従事。
株式会社リクルート
プロダクト統括本部 まなびデータプラットフォームグループ
データエンジニア 橘高 允伸氏
2019年リクルート新卒入社。データエンジニアとしてデータ基盤の開発・運用に従事し、データ基盤の移管プロジェクトなどに携わる。現在はデータプロダクトのバックエンド開発も担当。
株式会社リクルート
プロダクト統括本部 まなびデータプラットフォームグループ
データエンジニア 丹田 尋氏
2020年リクルート新卒入社。データエンジニアとしてデータ基盤の開発・運用に従事し、データ基盤の移管プロジェクトなどに携わる。現在はデータ基盤の開発に加え、MLOps周りも担当。
『スタディサプリ』のデータ分析基盤の進歩と調和
最初に登壇したリクルートのデータエンジニアマネージャー 戸井田明俊氏は、『スタディサプリ』のデータ基盤の変遷について説明した。
データ基盤が立ち上がったのは2016年。BIツールの導入、SaaSとの連携、サーチ機能やレコメンド機能の開発といった流れで進み、2020年にBigQuery を中心としたGCP 環境へリプレイスし、今に至る。
BigQueryデータの利用状況に対し、戸井田氏はデータ量自体は中規模だと言う。だが、テーブル6000個以上、クエリー数/日が5000個以上、200個以上あるデータセットを8人のメンバーで日々対応するのはそれなりの苦労がある。
マスターデータは、アプリユーザーの属性や契約・課金情報など。クライアントデータは、アプリやクラウドデバイスからの取得するログ。サーバーサイドデータはサーバーから逐次ストリーミングで送られてくる学習データのログ。SaaSデータは、マーケティング部門などが使用している外部SaaSから得られるデータだ。
具体的なデータのモニタリング・分析や、開発・運用の事例についても紹介された。 「データのモニタリング・分析活用シーンでは、事業部や営業部などが日々データをもとに事業の意思決定をするが文化として根付くように意識しています」(戸井田氏)
また、CRMなどのデータ活用シーンにおいても、データをもとに行ったコミュニケーションや訴求のアクションログもフィードバック。より良い施策に繋ぐPDCAをまわすことを心がけているという。
課題解決を通じて、メンバーが大きく成長した
データ基盤を立ち上げ、運用していく中で、利用ドメインやユーザーはもちろん、ステークホルダーが増加していったことで、大きく3つの課題が生じるようになっていった。
「慢性的にキューが溜まるため、アドホックなクエリを投げることが難しくなりました。また、OSSのミドルウェアをいくつか使っていましたが、バージョンアップの負担が大きくなっていました。MLシステムはGCPのサービスを使っていたため、旧基盤のTreasure Dataとはシームレスに連携しませんでした」(戸井田氏)
こうした課題を解決しようと、新基盤の構築に取り組む。まずは基盤を、小中学校・高校向け、English向けと2つに分けることを決めた。アプリケーションID、開発体制や技術スタックも異なるのが理由だ。小中学校・高校向けデータ基盤は「Platon」、English向けデータ基盤は「Organon」と名づけられた。
次は技術選定・実装のポイントをかためていった。8人というチーム体制を考慮し、技術スタックはなるべく広げず、共通とする。OSSのバージョンアップのネックも含め、マネージドサービスを積極採用することなどを決めた。
このように方針を定めていくと、GCPが最適だという結論に至る。ただ将来のことも考え、他のクラウドサービスへの移植性を考慮。続いて、「属人化しないことをポイントにする」運用方針も固めていった。
SLA(Service Level Agreement)を定め、週次で振り返る。障害が発生した際は作業ログを残す。属人化しそうな対応の際は、ペアプロで進める。さらに、CI/CDの整備などを決めていった。
そして2019年1月、データ基盤移管プロジェクトはスタートする。メンバーの多くがGCPの知見が少なかったため、検証期間を長く取ることを意識。旧データと完全に入れ替わる約2年後までの半分以上の期間を、技術検証・共通部分の開発に充てた。
戸井田氏はプロジェクトによって得られた成果をまとめ、最後に振り返りを述べ、セッションを締めた。
「今も志半ばではありますが、先の課題がシャープに解決できたこと。困難なプロジェクトを乗り越えたことで、メンバー一人ひとりが成長したことが、マネージャーとしては嬉しく思っています」(戸井田氏)
『スタディサプリ』でのBigQuery移管と実践的活用術
続いては、データエンジニアの橘高允伸氏が登壇。旧データ基盤のアーキテクチャには、「集計クエリーのリソース枯渇」「一貫性のないデータセット・権限管理」「データの不整合」「中長期のメンテナンス困難」の課題があったと説明した。
集計クエリリソースの枯渇については、次のように補足している。
「アドホックなクエリだけでなく、基幹集計も慢性的に遅延。強制終了するような対応もしたが、始業時刻の10時に間に合わない状況でした」(橘高氏)
同じデータセット内に、レイヤーの異なるマスター、ログ、データマートといった複数形式のテーブルが混在していた。そのためクエリを書く際、パーティションの有無や指定方法を、テーブルごとに配慮する必要があった。
Adminが乱立するなど、どのチームがどのデータセットに対して、どのようなアクセス権限を持つかも管理・把握できていなかった。
レコードの重複が発生しているにも関わらず、BIツールのダッシュボードを見るまで気づかない状態でもあった。微妙に異なるCASE文がクエリ間に散在していたが、意図的なのかどうか判断が難しい。一部のデータが古い状態でも集計が進んでしまう。データの不整合に関する問題もあった。
基幹集計クエリは300個以上。調べていくとスケジュールクエリなど、基幹集計に不要と思えるクエリもあったが、「判断が難しく迂闊に停められない状況だった」と橘高氏。 そのほかにもデータやクエリに関する課題は山積みだった。
BigQueryの移管と平行して課題解決に取り組む
このような課題を新しいデータ基盤、BigQueryにすることで解決していった。
まずは「集計クエリのリソース枯渇」について。集計処理が高速化したことで、これまで60分ほどかかっていたあるテーブルの集計時間は1分ほどに短縮された。また、従量課金モデルのため、コストを意識してクエリを書くようになった。さらに新しいデータ基盤では、リソースのモニタリング整備も行っている。
「Lookerでダッシュボードを作成し、BigQueryのクエリ料金、ストレージ料金を日次、月次で見れるようにしました。クエリスキャン量も、ユーザーごとに確認できると同時に、制限を設定しています」(橘高氏)
旧基盤では、ひとつのリソースを異なるプロジェクトで食い合っていたが、新しい基盤では、サービスアカウントによる基幹集計、アドホック集計、BigQueryの実行プロジェクトを分割した。
「一貫性のないデータセット・権限管理」では、データセットレイヤーの再設計を行った。具体的にはプロジェクト・データセットの種類により、より細かい単位で分割した。
パーティションの方式もプロジェクト・データセットごとに明確化することで、指定方法が有無も含め、より直感的に分かるようになった。アカウントの権限管理においては、以前は手動管理であったが、チーム単位、Terraformでの管理とした。
また、管理者以外はサンドボックス環境へのみ書き込み権限を持つようにした。本番のLooker環境からはレポート用のプロジェクトのみ参照可能と、Lookerの権限管理も方針を定めた。
「基幹集計処理の管理外で、新たな指標定義を防止することが目的です。利用者がサンドボックス環境で自由に作ったテーブルを、Lookerで自由に参照できてしまうと、どれが正しい指標か分からなくなると考えたからです」(橘高氏)
データの不整合とクエリのメンテナンス性に対する取り組み
「データの不整合」に対しては、移管時に、データの検証作業を網羅的に行うことで対応。旧基盤の集計テーブルをBigQueryにコピーし、差分を検証していった。
まずは、粒度の大きい集計を行った。その上で差分がありそうなときは、BigQueryのクエリでバグがないか確認。ある際は、詳細な差分を検出するために、BigQueryのEXCEPT DISTINCTを利用した。
「EXCEPT DISTINCTを多用することで、レポートレベルで差分の確認、原因調査をスムーズに行うことができた。旧データ基盤も平行運用し、検証で問題ないテーブルから移管することで、データ基盤を止めることなく移管業務を行うことができました」(橘高氏)
日時集計のデータバリデーションも整備した。テーブルごとにyamlファイルでバリデーションタスクを管理。ASSERT文を用いたクエリの実際のコードも紹介した。このyamlファイルから、Composerでタスクを自動生成することで、日次で、バリデーションタスクを実行しているという。
データの有無、レコード数が単調増加するテーブルであれば、ユニークを期待するカラムで、バリデーションがチェックできる環境も整備。さらに、UDF(ユーザー定義関数)で処理を共通化し、対応漏れを防止する対策を行っている。
最後は「中長期のメンテナンス」への取り組みだ。まずは、移管タイミングでクエリの削減を行った。移管対象となるクエリを一度すべてスプレッドシートに並べ、必要性や優先度を確認していった。
確認方法は、LookerAPIを使用。各グラフから参照されているテーブルをスプレッドシートに書き出すスクリプトを書き、そのスプレッドシートでテーブル・Lookerから参照の有無を確認した。
参照されていないと分かったクエリは、念のため利用者の存在を関係者に確認し、いないと判断された場合は廃止とした。同対策を行ったことで、Englishの基幹集計だけでも不要なクエリが約40%顕在化され、実際に削減。書き換えコストの大幅削減に寄与した。
クエリの管理に関しては、以前も主要な集計クエリはGitHubで管理していたが、新しい基盤では、BigQueryのスケジュール機能は使わず、実行基盤を構築した。
データアナリストは、クエリを投げるタイミングやどのスプレッドシートにエクスポートしたいのかといった設定を、yamlファイルに書き、プルリクエストを出す。
リクエストを受けたエンジニアのレビューがマージされ、Cloud Composerでデプロイされ、指定された処理が実行されるというフローだ。CIでのテストも行っているという。
「プルリクエストを出したときに、CIでSQLをBigQueryでdry runして、クエリテストを実行しています。このテストを入れることで、シンタックスエラー、テーブル・カラム名のタイポ、パーティションの指定忘れをチェックすることができ、プルリクエストレビューコストが軽くなりました」(橘高氏)
さらに、Google Cloud のメタデータ管理サービス、Data Catalogを導入。スライドで示したとおり、データ・マネジメントの強化にも取り組んでいる。
チームにおけるメタデータの管理方法にも取り組む。スライドの右側に示されているように、タグ情報とテーブル説明はyamlで、スキーマ・カラムの説明はjson。両データを人手で管理・編集する体制としている。
オペレーショナルメタデータの管理についても説明された。Cloud LoggingのBigQuery監査ログを、BigQueryへエクスポートして使用。エクスポートしたデータに、Composerで日次集計処理し、Data Catalogのタグ情報を更新している。実際、右側のタグのサンプル情報を見ると、Lookerのアクセス回数は0。ユーザーのアクセスカウントが週で489回であることが分かる。
「オペレーショナルメタデータを用いることで、継続的なテーブルの棚卸しが継続できやすい環境となっています」(橘高氏)
『スタディサプリ』のデータ基盤を支えるETLとパイプラインの技術
セッションの締めは、データエンジニアの丹田尋氏が登壇。まずは移管後、現在の『スタディサプリ』のデータ基盤アーキテクチャを示し、データのパイプラインを説明した。
クライアント、サーバーサイド、DBなどからembulkなどのツールを介して日々、DWHであるBigQueryにデータは集められる。その後、BigQueryでデータ集計を行い、外部にデータ連携を行う。エクスポート先はLooker、スプレッドシート、Tableau、Salesforce、Marketoなど。CRMでも活用されている。
全体の処理はGCPが提供するApache Airflow ベースのフルマネージドワークフローオーケストレーションサービス、Cloud Composer(以下、Composer)で制御。その利点を、丹田氏はこう語っている。
「スライドのように、タスク間の依存関係がひと目で分かります。また、タスクの実行時間、ランディングタイム、DAGのガントチャートも見ることができる。どこにボトルネックが発生しているのかも特定できるため、開発に集中することができます」(丹田氏)
だが、日次の処理時間や労力は激減しなかった。そこでComposer全体での日次処理時間の状況を調べると、データ転送タスクがBashOperatorで90%を占めていた。つまり、データ転送処理のパフォーマンスが改善できれば、全体の高速化が見込めることが分かった。
また、データの定常処理を支える運用の負担が大きく、大きく4つの課題があることが分かった。
データの定常処理を効率化するパフォーマンス面における取り組み
パフォーマンス面では4つの工夫を行った。1つは、日次処理の平準化である。以前は外部データ、ログ、マスターデータを同じ時間帯に取り込んでいたため、Composerで使われているGKE(Google Kubernetes Engine)ノードの負荷が高くなっていた。
また、GCE(Google Compute Engine)にSSHで接続して処理を走らせるタスクも多くあり、リソースを逼迫したが、平準化することである程度解決できた。
2つ目はComposerのGKEノード数を、負荷に合わせて調整する仕組みを取り入れた。全体の処理を分散させても、負荷の濃淡が生じていたからだ。
多くのデータを取り込む必要があるため、ログ、マスター、外部データの取り込み期間をピークタイムと定義した。また、タスク量に合わせ、ノーマルタイム、アイドルタイムも定義。GKEのノード数を1日3段階変更させる設定とした。ノード数変更のgcloudコマンドを実行するタスクを各間に入れ込むことで実装を実現した。
3つ目に、並列や直列などのレーンを設けて、タスク処理を調整する仕様とした。突発的にログ取り込み量が増えた際、直列にして負荷を抑えることができるからだ。逆に、障害対応など急ぎたい場合は9並列などで処理を速く終わらせることが可能だ。
「レーンの調整においても、AirflowのVariablesで簡単かつ柔軟に変更できるので、大きな恩恵を受けています」(丹田氏)
4つ目の工夫として、EmbulkのCloud Runでの実行が紹介された。
データ転送処理の大部分を担っているembulkの処理は、これまでCompute Engine上で行っていた。すると、複数処理による同一リソースの食い合いが発生し、負荷を減らすコストもかかっていた。
そこで、サーバーレスのコンテナ実行環境Cloud Runで実行。具体的にはCloud RunでAPIサーバーを立てる仕組みを構築した。すると、スケーラビリティ拡充の副次効果も得られた。
ログの急増に対して、対応した事例も紹介された。
データの定常処理を効率化する運用面における4つの工夫
続いて、データ基盤運用の課題に対する4つの工夫が紹介された。
1つ目は 、SLA(Service Level Agreement)を定め、モニタリングを徹底したこと。
2つ目は、CI/CDとインフラコード化の徹底で障害を予防したこと。CIツールはGCPのCloud Buildを、インフラのコード化ではTerraformを導入し、GCPコンポーネント管理も行い、構成の再現性を担保するようにしている。
3つ目の工夫は、障害を迅速に検知するために監視項目を整理。アラート設定を行い、障害を迅速に検知する仕組みを取り入れた。
4つ目は障害対応をスムーズにする工夫だ。具体的にはエスカレーション対応の条件、対応方法・コツ、対応の心構え、対応時のログをドキュメントとして残すことで、誰でも対応ができるようにした。もうひとつは、スケジュールの集約である。
以前の仕組みは、上流のタスクAで障害が発生した場合、タスクB・Cは手動で止める必要があった。タスクAを再実行した際も同じく、再び手動でタスクB・Cを再実行する必要がある。そこでwaitタスクを挟み、スケジュールをひとつにまとめたことで、障害対応のコストが激減した。この4つの工夫をPDCAすることで、さらにエンハンスしているという。
最後に丹田氏は今後の展望として、Composerのさらなるロバスト化の実現と、新データ基盤とMLOps基盤の連携強化を挙げ、セッションを締めた。
【Q&A】参加者から寄せられた質問を紹介
セッション後は、Q&Aタイムが設けられた。その中からいくつか紹介する。
──TableauとLookerを両方運用している理由は?
戸井田:Lookerはメインで使い、事業全体のKPIにも活用しています。Tableauは営業組織など、一部のチームで運用しています。
──分析者がレポート以外のプロジェクトにアクセスしたい場合の対応
橘高:分析者のアドホックなクエリは、レポート以外のプロジェクトにもアクセスできるようになっています。ただ、テーブルの作成や削除の権限は、サンドボックス環境のみにしています。Lookerについても、本番環境とは別にサンドボックス環境用のモデルを用意することで、サンドボックスを使ったダッシュボードも作れるようになっています。
──BigQueryの利用においてflat rateは検討しなかったのか
戸井田:コスト試算した結果、現状はオンデマンドの方が安かったので、オンデマンドとしました。将来的には検討していますし、 リクルート社内の他部署はフラットレートの方が多いです。
──dbtなどのツールを使ったバリデーションを使わない理由
橘高:データ基盤利用者にとってdbtの学習コストがやや大きかったことから、移管時は見送りました。新しい基盤になって1年経ったので、改めて検討するフェーズだと思っています。
戸井田:一部のコンポーネントでは使っているので、その知見をもとに全体での利用に広げていきたいと考えています。
──新基盤で劣化したポイントはあるか
戸井田:劣化ではありませんが、Treasure Dataではデータユーティライゼーションという管理画面があり、クエリの実行量やストレージの消費状況など、ひと目で確認できるメトリクスがありました。Treasure Dataも含め、個人的にこの仕様がとても好きだったのですがGCPにはないので、Lookerを使って自分たちで自作しています。
──目的ごとにGCPのプロジェクトを切っているが、Composerはどのプロジェクトで動かしているのか。プロジェクトをまたぐことによるデメリットはないのか
丹田:Composerを動かしているプロジェクトは、基幹集計処理などのタスクを実行するプロジェクトとして他とは分けて作成しています.他プロジェクトと分かれているデメリットは特に感じていませんが、権限管理をプロジェクトごとに振る必要があるため、煩雑になるとは感じています。
──データセット数や分割の方針などで特に重視した点
橘高:マスター系、ログ系、データマートレポート系というように、プロジェクトは大きな種類で分けています。その中でソースの種類やエクスポート先などのさらに小さい単位でデータセットを区切っています。例えば、マイクロサービスのあるDBから取ってきているデータを1つのデータセットとして管理しています。
──制約の多いFirebase Analyticsを選んだ理由
戸井田:Firebase Analyticsは、BigQueryに入った後、データの整形が大変なため、自分たちでサーバーサイドのログトラッキングのエンドポイントを作る選択肢もありました。ただ、メンバーが8人しかいないことを考慮すると、マネージドサービスを使った方が、トータルの運用コストは下がると判断しました。
──embulkはAWS、GCPどちらの環境で動いているか
丹田:GCPのCloud Runで動いています。基本的にはデータがAWSにあっても、GCP側からデータをプルしています。
──embulkに定期的に送る機能はないが、Cloud runで定期実行しているのか
丹田:Cloud Run自体では、定期実行していません。Cloud RunはAPIサーバーを立てており、そこにリクエストを投げて実行しています。具体的には、Airflowのタスクの中で、Cloud Runへのリクエストを投げています。スケジュール中で、embulkのタスクをトリガーするようにしています。
──embulkによるマスターデータETL処理において
丹田:基本的な思想として、embulkの中でtransform処理は できるだけ行いません。分析チームが分かりづらくなるからです。
──1日に実行するDAG、タスクの定義数
丹田:バリデーション用、デイリー用のDAGを毎日実行しており、後者のボリュームが大きいです。embulkのタスクだけでも約500、集計やエクスポートも含めると700ほどの規模感です。
──Treasure Dataから移管するとき特に苦労したこと
橘高:基幹集計だけで300以上もあり、チームで手分けして作業しましたが、1人で作業することもあり、EXCEPT DISTINCTでバグを探していました。例えば、不等号の向きが逆なバグがあり、それを見つけるだけに数時間を要したこともありました。
戸井田:不等号の向きで思い出しましたが、PrestoとBigQueryでDATE_DIFF関数の引数の順番が逆なんですが、僕がそこを間違えて橘高さんに指摘されたことは何度かありましたね(苦笑)