はじめに
こんにちは!スマートキャンプエンジニアの中田です。
直近で、BOXIL SaaSのDBのデータをBig Queryへロードするために利用していたETL基盤をリプレイスし、運用コスト・転送時間を改善しました。
旧基盤 | 新基盤 | |
---|---|---|
運用コスト(料金) | 約 $750/月 | 約 $70/月 |
転送時間 | 約 1時間 | 約 10分 |
本記事では、そのリプレイスの背景や内容についてお話できればと思います。
リプレイスの背景
旧ETL基盤の構成
弊社のデータ分析基盤はもともと以下の画像のような構成になっていました。
今回リプレイスしたETL基盤は、画像真ん中あたりに位置するEC2(Digdag + Embulk)の定期処理サーバーです。
c4.large
サイズのインスタンス * 4台で処理対象のテーブルを分割して請け負っており、それぞれが毎時00分に定期処理されるような構成になっています。
Big Queryには全件洗い換え方式で実行ごとに最新日付でシャーディングテーブルが作られます。 これは、DBの状態を時間軸で辿れるようにしておくための運用です。
課題感
運用していたETL基盤には大きく以下の3つの課題感がありました。
転送時間
1つ目は転送時間の問題です。
旧ETL基盤で、BOXIL SaaSのDBのデータをBig Queryにロードするまでの処理に1時間弱の時間を要していました。 そのため、定期処理の頻度はhourlyとなっています。
転送時間を短縮すると、実行頻度も上げられます。 Big Queryに送られたデータはBIツールを通してビジネスサイドで分析に利用しているため、最新のDBが分析に利用できるまでのラグを短縮するためにも転送時間を改善したいなと思っていました。
コスト
2つ目はコストの課題です。
コスト(料金)
BOXIL SaaSのDBのデータ量は約5GBです(一部転送対象に含めていないログテーブル等は除く)。
ETL処理を行なうためにc4.large
タイプのEC2インスタンスを4台稼働させていたため、月々$750ほどの料金がかかっていました。
データ量が膨大なわけでもないため、もっと安価に運用可能な方法を検討したいなと思っていました。
コスト(時間)
リソースの枯渇など継続運用によるサーバー起因の問題が発生した場合にはサーバーに入り調査・解決する必要がありました。 一時期は高頻度で上記のような問題が発生しており、管理にコストがかかっていました。
また、複数台のインスタンスで処理対象のテーブルを分割しているため、処理が追いつかず台数を増やす場合には、新たに設定してインスタンスを立てる、テーブル分割の設定ファイルを都度チューニングする、といった手作業でのセットアップが必要で手間でした。
汎用性
3つ目は汎用性の問題です。
旧ETL基盤は上記の通りBOXIL SaaSのDBにのみ適応されていました。
一方で弊社には複数のプロダクトが存在します。 個別にデータ分析のための仕組みを持つプロダクトもあるものの、ETL処理の流れをBOXIL SaaS同様に一貫して行いたいという要望がありました。 また、新規のプロダクトができた際にもなるべく工数をかけずにデータ分析基盤を整えたいため、ETL基盤にも汎用性が求められます。
しかし、旧基盤はIaCされておらず、BOXIL SaaSに閉じた作りになっていたため、各環境に反映するには同様の基盤を手作業で組み直す必要がありました。
新ETL基盤
前述の課題感を低減するべく、新たに作り直したETL基盤が以下になります。
構成
新基盤は上記のサーバーレス構成で作成しました。
上記の構成はTerraformでコードベースで管理しており、Moduleとして切り出しているため各WorkspaceのコードでModuleにパラメーターを注入して利用することで汎用可能となっています。
全体の流れと各処理の役割について簡単に説明します。
Step Function
画像の通りAWS Step Functionsのステートマシンでワークフローを作成し、以下の流れでステップ実行しています。
- Glue Jobで任意のストレージ -> S3にデータ転送
- LambdaでS3 -> Cloud Storageにデータ転送
- LambdaでCloud Storage -> Big Queryにデータ転送
ワークフローはCloudwatch Eventでルールに基づいてスケジュール実行するよう設定しています。
AWS Glue Job
Glue Jobでは任意のストレージからデータをロードして加工後、S3に書き込む処理を行っています。 S3に書き込むファイルの形式は旧基盤でJSONだったのに対し、新基盤ではファイルサイズが小さく・読み込み効率の良いParquetを採用しました。
環境変数以外では、このジョブスクリプトのみTerraform側で可変に設定できるようにしており、以下の処理を環境に合わせて書き変えます。
- MySQLやPostgreSQL、Salesforce API等読み込み対象のストレージへの接続処理
- 読み込み対象から排除したいテーブルの指定、データの加工処理
AWS Lambda
Lambdaでは以下の処理を行なう2つの関数を定義しています。
- Amazon S3 -> Google Cloud Storage
- Google Cloud Storage -> Big Query
Lambdaには転送以外の処理は持たせず、Storage to Storageのバケツリレーのみ行っています。 ランタイムはどちらもGoで、速度を上げるためにそれぞれデータの書き込み部分はgoroutineを使って並列処理するようにしています。
成果
新しいETL基盤の構築により、旧基盤と比較して以下の改善ができました。
転送時間
BOXIL SaaSのDBのデータの転送で約1時間 -> 約10分に改善できました。
現状、転送頻度はこれまで同様にhourlyのままで設定していますが、環境ごとにCloudwatch Eventルールのcron式を調整できるようにしているため頻度を倍にも調整可能です。
コスト
コスト(料金)
BOXIL SaaSのDBのデータの転送で月当たり約$750 -> $70に改善できました。
旧基盤では常時稼働していたサーバーが、新基盤ではサーバーレスにスポットで実行されるようになり、大幅にコストを削減できました。
コスト(時間)
サーバーレス構成にしたことで、サーバーの継続運用による問題で手を焼くことは少なくなりそうです。
また、Terraformを利用して汎用性を考慮してコードベースで管理しているため、各環境でこのETL基盤の構成を再現することも容易になりました。 別環境での基盤構築にかかる工数も削減できていると言えそうです。
汎用性
Terraformで構成をModuleに切り出しているため、各環境下で汎用的にETL基盤を再現できます。
環境ごとに作成するようにしているGlue Jobのスクリプトの記述も、ストレージタイプが同じ場合はほぼほぼ同様のコードで問題ないため、新しいタイプのストレージを利用したい場合のみ接続部分の記述に少し工数が取られそう、というくらいの肌感です。
まとめ
いかがでしたでしょうか?
今回はETL基盤のリプレイスについてお話ししました。
ETL処理を実現する方法は多様にあるため、どのサービスをどう組み合わせて作るのが効果的かなと悩みます。 構築にあたってはいくつかの方法を検討したうえ、効果を比較していく過程にもっとも時間がかかりました。
構築をご検討の際に本記事を一例として参考にしていただけますと幸いです。
最後まで読んでくださりありがとうございました!