Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

Gunosy のデータ活用を支える統合データ基盤 Baikal の話

はじめに

DRE チームの hyamamoto です。

新卒の方々が入社されて 4 ヶ月ということで、時の流れの速さを感じています*1。なお、現在、新卒の方々でリレー方式でブログを書いているようなので、気になる方はこちらもどうぞ。 私も去年のことを思い出しながら、興味深く読ませていただきました!

data.gunosy.io

さて、話を本題に移すと、今回は Gunosy のデータ活用を支える統合データ基盤 Baikal についてお話したいと思います。 当時私は入社前でしたが、DRE チーム発足当時から取り組んできたプロジェクトということもあり、ご紹介できることを嬉しく思います。

Baikal について

Baikal は社内の統合データ基盤プロジェクトのことで、世界で最も透明度が高い湖であるバイカル湖にちなんで名付けられました。 透明度の高い、管理・整備の行き届いたデータレイクを作るぞということが由来です。 今回はこの Baikal について、利用している技術やそのアーキテクチャについてお話したいと思います。

Baikal を支える技術と工夫

「管理・整備の行き届いた」を目指す Baikal では次のような技術を採用し、データやワークフローを管理しています。

これから示す手法が由来する思想はシンプルで、疎結合な管理とコード化による属人性の抑止にあると思っています。 私自身、オンボーディングの際は GitHub 内で検索をかければ何かしら出てくるので、全体感から詳細まで、対応すべき粒度感に合わせて、比較的容易に把握できたように感じます。

AWS アカウント

Baikal は Baikal 単体での AWS アカウントを持っており、他のプロダクトからは切り離された環境を持っています。 また、dev, stg, prd 環境についてもそれぞれで 3 つの Baikal 向けの AWS アカウントも保持しており、開発環境が本番環境に対して影響を与えることが無いような設計になっています。

dev 環境は個人による破壊的な操作が許容されており、 クラウド上のリソースを使いつつ、スピード感のある開発が可能となっています。

Terraform

Baikal 上のインフラは全て Terraform によって管理されています。 Terraform Workspace を利用した運用になっており、各 dev, stg, prd と AWS 環境に対応しています。

また、データ基盤としては Glue Catalog によるスキーマ管理と Lake Formation による権限管理を利用しており、これらの設定については Terraform を管理するレポジトリを他のインフラ管理するものから分離しています。

結果 Database や Table がひと目見て理解できる Project Structure になっており、このレポジトリ自体がデータ基盤内の DB, Table, 権限を示すドキュメントとして機能しています。 tfstate も分離されるので CI/CD のワークフローにかかる時間を下げることにも貢献しています。

ワークフロー基盤

ワークフロー基盤については過去の記事でも紹介されているので、こちらも参照してください。 tech.gunosy.io

基本構成としては EKS 上に Digdag を立ち上げてワークフロー基盤としています。上述の記事内にもありますが、Digdag から更に K8s Job を実行できる構成になっており、コンテナ化さえしてしまえば任意のロジックが Digdag 管理のもと実行可能な環境となっています。

EKS の設定、監視の方法については下記記事にも詳しく解説されており、弊チームの環境はこれに準拠しています。

tech.gunosy.io

tech.gunosy.io

Athena

Baikal ではデータ変換のほとんど*2を Athena で行っています。 Athena は CTAS をサポートしており、これによりクエリさえ書いてしまえば、サーバーレスに大規模データの処理および S3 上への配置をすることが可能です。

Athena の実行部分については、下記オペレーターを用いることでシームレスに Digdag から実行することが可能となっています。 github.com

この後紹介する内容と重複する部分もありますが、下記スライドにはこの構成に至った経緯なども書かれています。 speakerdeck.com

Lake Formation

Baikal に基づくデータ活用が進んだ1つの要因として Lake Formation の Cross-Account Access Permission が挙げられます。

Baikal 内で IAM を発行し連携することができるため、データの活用先としては BI ツールでの分析用途が主でした。 一方で、データ生成元 AWS アカウント(各プロダクトのアカウント)に貯めたデータを還元するというのが難しい状態でした*3

このような状況を打開したのが Lake Formation の上記の機能です。 詳細は公式ドキュメントに譲りますが、Lake Formation の権限管理により、Baikal 以外のアカウントにおいても、自身のアカウント内にある Athena テーブルのように扱うことができるようになりました。 結果、各プロダクトの AWS アカウント内の ML モデルの学習にも Baikal のデータを活用できるようになりました。 また、その結果各アカウントで実行していた ML モデル向けの前処理的なバッチについても Baikal のワークフローに統合できるようになりました。

アーキテクチャ

それでは、アーキテクチャについて触れていきたいと思います。

f:id:hiro-o918:20210806123043p:plain
アーキテクチャ

アーキテクチャ全体は上記のような図になります。 大きくまとめると

  • embulk を中心とした K8s Job によるデータ抽出・配置
  • Athena を用いたデータ変形
  • Glue, Lake Formation を用いたデータ共有

になります。

それでは以下でいくつかのパートに分けて見ていきたいと思います。

Extract & Load

ここでは Baikal におけるデータの抽出について示します。 Baikal 自身はサービスを持たないため基本的には社内の AWS アカウントや社外 API と連携することで データの取得をしています。 取得されたデータは workspace と呼ばれるバケット上に一時配置され、 その後の変換に利用されます。

また、バケット上に配置されたタイミングで一時的な Glue Table として参照が可能になります。 この Table は後続の Transform で利用されます。

f:id:hiro-o918:20210806123517p:plain
抽出と配置

データ生成元 AWS アカウントにある RDS からデータ抽出

(上記図の上段)

データ生成元 AWS アカウントにある RDS からデータを抽出するためには、embulk を用います。 この際 embulk の処理は Digdag から K8s Job としてキックされます。

また、RDS が配置されている VPC は Digdag が実行されている VPC と異なるため VPC Peering を利用して通信をしています。VPC Peering については下記の記事が参考になりました。

dev.classmethod.jp

データ生成元 AWS アカウントにある DynamoDB からデータ抽出

(上記図の中段)

DynamoDB に関しても embulk を用いてデータ抽出をします。

DynamoDB は IAM によってアクセスコントロールを設定します。 具体的には DynamoDB に対する権限を保持したアカウントを該当するデータ生成元アカウント側で作成し、Baikal アカウントで AssumeRole できるようにします。 embulk Job はこの権限を利用して DynamoDB 内のデータを取得します。

社外の API からデータ抽出

(上記図の下段)

ここでは社外の API から分析に必要なデータを抽出します。 これは弊社プロダクトの広告枠に表示した各種 SSP の売上や、自社プロダクトのマーケティング目的で広告出稿した際のレポートを取得するような場合に利用しています。

こちらに関しても embulk の takumakanari/embulk-input-http を利用する事が多いですが、embulk 以外にもその仕様に合わせてロジックを記述したコンテナを立てて S3 上にデータを配置しています。

このように抽出の場面において、スケーリングしつつ、コンテナ化された Job の実行基盤があるのは非常に便利です。

Transform

workspace に配置されたデータの変換

Extract & Load で紹介した内容から、データ生成元アカウントにあるデータを Baikal アカウント内の S3 に配置し、また Glue Table として利用できるようになりました。

そこで、次に分析データとして公開するための加工を行います。 ここでは Athena で示したように CTAS を実行し、その出力先をデータの公開用バケットである warehouse にします。 CTAS 実行時に目的の構造への加工や分析しやすい Parquet 形式への変換を行います。 また、warehouse へ配置するタイミングで適切なパーティションの考慮もします。

データ生成元 AWS アカウント内の生ログ変換

f:id:hiro-o918:20210806135936p:plain
生ログの変換
ここではデータ生成元アカウントにある生ログを変換します。 生ログはデータ量も多いため、embulk のような方法でデータをコピーして Baikal で 2 重管理するのはコストや負荷面において課題があります。

そこでデータ生成元アカウントからバケット Policy を Baikal アカウントに付与することで、直接的な読み込みを可能とします。 その上で、データ生成元アカウント内の S3 パスに対する Glue Database および Table を Baikal 側で作成することで Baikal 内の Athena から参照することが可能になります。

しかしながら、この時点でログデータは JSON 形式なテキストであるため、その後の分析に適したデータ形式とは呼べません。そこで Athena を用いて構造化や Parquet への変換を行います。

Parquet 化されたデータは transient-warehouse という名前のバケットに格納されます。 warehouse とバケットを分けている理由としては負荷分散を目的にしています。

ウェアハウス内での加工

f:id:hiro-o918:20210806143929p:plain
ウェアハウス内での加工

更に、warehouse や transient-warehouse に配置されたデータで、分析用途がある程度定まったものについては、前もってテーブルの結合や集約をしておきます。(図中の紫の線) 生成されたデータは warehouse に格納され他のデータと同様 Glue に登録され、共有可能な状態になります。

Share

f:id:hiro-o918:20210806145429p:plain
シェア

Transform でも示したとおり、加工され transient-warehouse, warehouse に配置されたデータは Glue に登録され Athena による分析が可能となりました。 また、Lake Formation の機能を用いて Baikal アカウント内外や BI ツールへの共有も可能です。

今後の課題

DRE チームで運用しているデータ基盤について紹介しました。 最後に今後取り組んで行きたい内容についてまとめて終わろうと思います。

開発の一部を他チームへの委譲

以上の取り組みから、他チームから Baikal のデータを参照されるようになり、統合データ基盤として一定の役割を果たせるようになったと思います。 実際、新規プロダクト開発時にも Baikal が整備されていることで、スピード感のある開発に対して貢献できたと思います。

一方で、取り込むデータが広がった結果、データ生成元の生ログや Database 内のカラム変更を 1 つ 1 つ DRE チームが感知して修正を加えることは難しくなりました。

この手の変更作業はパターンも見えており、比較的容易に修正を加えられることからも、データ生成元に対して変更を加えたチームから PR が飛んでくるような世界線になればいいと感じています。

このための取り組みとして、DRE チーム以外の開発者に向けたドキュメント整備、LT 会での技術スタックの発表、ペアプロなどを進めています。

データ異常検知

ワークフローの実行成功は正常なデータ配置が行われていることの保証にはなりません。デグレや障害によってワークフローは成功しているがデータが取れていないということがしばしば起こり得ます。 そこで、配置されているデータそのものへの異常検知の仕組みを検証、導入していきたいと考えています。

BI ツールの導入

アーキテクチャの図にも登場しますが、弊社では SaaS 版の Redash を利用してきました。これまで非常にお世話になってきたのですが、EOL ということで、次の BI ツールの導入を検討しています。 Redash 導入当初からは会社の規模感も変わっているので、今の規模感に沿ったツール・運用選定ができればと思っています。

読んでいただきありがとうございました!

*1:いや、まじ社会人時間経つの早すぎでは....?

*2:一部は同じ K8s クラスタ上で Spark を実行しています。詳細な構成はこちら: https://data.gunosy.io/entry/spark-on-k8s-on-eks

*3:Cross-Account Role を作成し AssumeRole すれば取り込みはできるものの、生成元の Athena Table との結合にはひと手間が必要でお世辞にも直感的に使える状態ではなかった