ヌーラボブログリレー2024 for Tech Advent Calendar 2024の11日目の記事です。
こんにちは、RevOps部データインテグレーション課の大塚です。
弊社で約6年間運用してきたデータ基盤をAmazon AthenaからSnowflakeに移行した際の体験談をお届けします。
今回はインフラ構築について書きましたが、Snowflakeへの移行に至るまでの経緯や背景も18日に公開する予定です。お楽しみに!
本記事では、既存のアーキテクチャとSnowflakeへの移行プロセスを比較しながら、実際に取り組んだ内容をご紹介します。
目次
データ基盤のアーキテクチャ
Before: Amazon Athenaを中心とした構成
Amazon S3(以降S3と表記)とAmazon Athena(以降Athenaと表記)を組み合わせたシンプルな構成でした。
これまでのデータ基盤は、以下のような構成です:
-
- データストレージ: S3
- クエリエンジン: Athena
- ETL: AWS Glue Job、RDS Snapshot Export to S3、TROCCO(スプレッドシートのデータ)
データの加工もAirflow経由でAthenaのSQLを実行しています。
メリット
コスト効率が高い:
特に数百GB程度のデータ量であれば、JOINを重ねても高速に応答してくれるので、
AthenaとS3の組み合わせは非常に経済的です。
自動認識:
Glue CrawlerがS3上のデータを自動的に認識し、テーブルとして利用可能でした。データの登録作業が簡素化される点は特に便利です。
デメリット
スケールアップの難しさ:
データ量の増加に伴い、Athenaのクエリ実行時間が遅延する問題が発生する可能性があります。
時間単位でスケールアップすることは可能ですが、最低実行時間が1時間となり、クエリの状況に応じたDPUの調整をする必要があるなど制御が複雑になります。
ツールの制限:
Athenaに接続できるサードパーティのツールが限られており、Athenaを利用するためにAWSマネジメントコンソールを全ユーザーに開放することは、他のAWSリソースについての制御などを考慮する必要もあるため要件的に困難と判断しました。
Athenaを中心とした構成は、少数のチームで小規模のデータを収集、加工、提供しているうちはコストパフォーマンスよく利用できる構成だと思います。
After: Snowflakeを中心とした構成
新しい基盤では、以下の変更を加えました:
- DWH: Snowflake
- ETL: Airflow(SnowflakeのCOPY INTOを実行)
- データ変換: dbt
- BIツール: Tableau
メリット
スケーラビリティ:
Snowflakeは、データ量やクエリ負荷に応じてリソースを動的にスケールアウト・スケールアップでき、パフォーマンス不足を容易に解消できます。
またAthenaで応答が遅くタイムアウトしていたクエリも実行できるようになりました。
現在dbtではdefaultのWarehouseを設定しつつ、状況に応じてクエリ単位でWarehouseを切り替える運用を行っています。
使いやすさ:
ユーザーフレンドリーなUIや豊富なツール連携機能を提供しており、管理も容易です。
特にユーザー管理・権限管理がSnowflakeで完結するため、Athenaの場合と違って他のAWSリソースへの影響を考える必要がありませんでした。
デメリット
データの二重管理:
移行の段階ではS3とSnowflakeの両方にデータが存在するため、管理コストが一時的に増加しました。
既存のデータも徐々に移行を進めて行く予定ですのでコスト面については受け入れました。
テーブル定義の管理:
COPY INTOを利用してデータETLする際、Snowflakeのテーブル定義と元データの整合性を維持する必要があります。
テーブル定義はデータをコピーする上で必要なため、AthenaのInformation Schema、Glue CatalogからAPIを介してTerraformのファイルを自動で作成することで対応しました。
導入時の取り組み
Snowflakeへのデータ移行
Glueのパーティション構造で配置されたデータを、どうやってSnowflakeにコピーしようか懸念していましたが、SnowflakeのCOPY INTOコマンドでREPLACEを利用することで簡単に解決できました。
以下はSnowflakeの外部ステージを設定して、ファイルをテーブルにコピーする場合の例です。
s3://bucket-name/table-name/year=2024/month=12/test.parquet のようにパーティション構造の配置されたデータからyearとmonthを取り出しています。
copy into コピー先テーブル名 ( year , month ) from ( select REPLACE(SPLIT_PART(METADATA$FILENAME, '/', -3),'year=','') as extracted_value # この行の部分で解決できます。 REPLACE(SPLIT_PART(METADATA$FILENAME, '/', -2),'month=','') as extracted_value # この行の部分で解決できます。 from @ステージ名 )
Athenaで使用していたS3データは、これを上手く利用することで変更することなくSnowflakeにデータ移行することができました。
インフラ管理
インフラコード管理にはTerraformを採用しました。これにより、開発環境と本番環境の構成を一貫性を持って管理でき、手動変更の差分も簡単に把握可能になりました。特にRoleとWarehouseの管理について、初期段階で適用した内容を記載します。
Role
Role同士で継承関係を持つことができ、権限を役割として設定することができます。種類は、以下に説明する二種類があるので失敗談を踏まえて説明します。
Account Role
ユーザーに付与されるロールで、初期段階で以下の3つを準備しました。
- ACCOUNTADMIN(サービス管理者)
- DATAENGINEER(データ編集者)
- ANALYST(データ分析者)
この辺りは役割に応じて作成していくと良いと思います。
Database Role
Databaseに付与されるロールで、以下の2つを準備しました。
- readwrite(データ編集権限)
- readonly(データ参照権限)
DATAENGINEERとreadwrite、ANALYSTとreadonlyを紐づけました。
なぜこのように分けたかというと、Account Roleでも同じように権限の設定が可能だったため、構築当初は全部Account Roleで作成してしまいました。Terraformのリソースページをリソース毎に確認を進めていくと設定できそうなもの設定してしまった形です。
どうなるかというと、DATAENGINEERに、readwriteを継承させてしまうとSnowflakeの画面上(Snowsight)でロールを切り替える操作をする際に、DATAENGINEERとreadwriteが選択肢に出てしまいUX的にイマイチになってしまいました。
readwriteはどちらかというと内部的な設定のものなので、特別な理由がない限りはAccount Roleだけで管理する方法は避けたほうが良いかと思います。
以下は、Account RoleとDatabase Roleを結びつけるTerraformの例です。
# DATAENGINEER AccountRoleの作成 resource "snowflake_account_role" "dataengineer" { provider = snowflake.useradmin name = "DATAENGINEER" comment = "dataengineer role." } # DATAENGINEERが利用するreadwrite DatabaseRoleの作成 resource "snowflake_database_role" "readwrite" { database = snowflake_database.sampledb.name name = "readwrite" comment = "database role for dataengineer account role" } # DATAENGINEERとreadwriteの紐づけ resource "snowflake_grant_database_role" "grant_dataengineer_role" { database_role_name = snowflake_database_role.readwrite.fully_qualified_name parent_role_name = snowflake_account_role.dataengineer.name } # readwriteの編集権限を作成 resource "snowflake_grant_privileges_to_database_role" "grant_table_wirte" { privileges = ["SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE"] database_role_name = snowflake_database_role.readwrite.fully_qualified_name on_schema_object { all { object_type_plural = "TABLES" in_database = snowflake_database.sampledb.name } } }
Warehouse
Snowflake上のクエリ処理などを行うコンピュートリソースのことです。サイズは、XS、S、M、L、XL、2XL…と10種類ありますが、処理能力、コスト共にひとつ上げると倍に増えていきます。
初期段階で利用したWarehouse
ユーザーが利用するXSMALL、SMALL、MEDIUMを3つ準備しました。デフォルト設定には、XSMALLを設定してもらっています。
またサービスが利用するものに関しては、それぞれ以下のように分けました。
サービス | Warehouse |
Airflow | AIRFLOW(LARGE)、AIRFLOW_XLARGE |
dbt | DBT(SMALL)、DBT_MEDIUM、DBT_LARGE |
Tableau | TABLEAU(XSMALL) |
サービス毎に分けておくことで、他のサービスに影響を与えないという点はもちろんですが、クエリ履歴を調査したり、コスト確認もWarehouse毎に集計されますので利用状況も確認しやすいので分けることにしました。
まとめ
本記事では、Amazon AthenaからSnowflakeへのデータ基盤移行によるアーキテクチャの変更と、移行中の取り組みについてご紹介しました。
移行を進める中で感じたことですが、Snowflakeの機能は日々進化しているので、今後も新しい機能を取り入れつつ、引き続き活用方法を模索しながら、さらに便利で管理しやすい基盤を目指していこうと思います。
この記事がAthenaの制限に課題を感じている方の参考になれば幸いです!