はじめに
現在フリーランスで活動しているエンジニアです。エンジニア歴は4年目になります。
AWSについては業務で触った経験はあるものの、「マスターしている」と言えるレベルではなく、
特に今回扱う Step Functions / Athena / Glue はほぼ初学習の状態からのスタートでした。
今回、CloudWatchに記録されているAWS操作ログを集計し、「どんなAWS操作をどれくらい行ったか」を学習記録として自動生成する仕組みを構築しました。
使用技術は以下です。
- Step Functions
- Lambda
- Athena
- Glue
- S3
- EventBridge
※ 本記事では「演習中に迷った点」と「それを解決するために調べた技術背景」に焦点を当てます。
迷ったこと①
Step Functions → Lambda → Athenaクエリ実行後、結果を待たずに次へ進んでしまう
何に迷ったか
Step FunctionsからLambdaを呼び出し、
Lambda内でAthenaのクエリを実行していました。
しかし、
- クエリ実行後すぐ次のステートに進む
- まだAthenaのクエリが終わっていない
- 結果が空 or 未確定の状態になりStep Functionsがエラーで止まってしまう
という問題が発生しました。
調べたこと(技術的背景)
Athenaのクエリ実行は 非同期処理 である、という点が重要でした。
AthenaのAPIは主に以下の流れになります。
-
StartQueryExecution
→ クエリを投げるだけ(完了は待たない) -
GetQueryExecution
→ 状態を取得する(RUNNING / SUCCEEDED / FAILED)
つまり、
Lambdaで
StartQueryExecutionを呼んだ時点では、
クエリは「開始した」だけで「終わっていない」
という仕様でした。
このため
Step Functions側で「完了を待つ仕組み」を作る必要がある
と分かりました。
どう判断したか(設計)
Step Functionsで以下のループ構成を作りました。
-
Waitステートで数秒待機 -
GetQueryExecutionStatusを実行 -
Choiceステートで状態を判定-
SUCCEEDED→ 次へ -
FAILEDまたはCANCELLED→ エラーとして停止 - それ以外 → 再度
Waitに戻る
-
擬似フロー:
StartQuery
↓
Wait
↓
GetQueryExecutionStatus
↓
Choice(完了?)
├ Yes → 次へ
└ No → Waitへ戻る
このようにすることで、
- Athenaの完了を確実に待つ
- Step Functionsのステートとして処理が可視化される
というメリットが得られました。
迷ったこと②
Athenaクエリ結果をStep Functions間でどう渡すか
何に迷ったか
Athenaのクエリ結果を
- 次のステート
- 次のLambda
に渡す必要がありました。
しかしStep Functionsでは
ステート間で扱えるデータサイズに約256KBの制限があります。
現状そのまま渡しても制限内に収まりそうではあるが、将来的に
- ユーザー数が増える
- ログ件数が増える
と、「結果をそのままJSONで渡す」方式では 上限を超える可能性が高いと感じました。
調べたこと(技術的背景)
調べて分かったポイントは以下です。
- Step Functionsは「大量データの受け渡し」に向いていない
- 大きなデータは
- S3
- DynamoDB
などの外部ストレージに逃がすのが定石
また、Athenaはもともと
クエリ結果をS3に保存する仕組み
を持っているため、
- 結果データ → S3
- Step Functions → S3のパスのみ管理
という設計が自然だと分かりました。
どう判断したか(設計)
- Athenaの結果はS3に保存
- Step Functionsでは「S3の保存先パス」だけを受け渡す
構成にしました。
これにより、
- データ量に依存しない
- 将来のユーザー増加にも耐えられる
というメリットを得ました。
迷ったこと③
GlueのprojectionとS3のパス構造が噛み合わない問題
何に迷ったか
Athenaでログを取得するため、
Glueのテーブルで partition projection を使用していました。
S3のパス構造の一部に accountid が含まれており、
s3://bucket/logs/accountid=123456789012/...
のような構成でした。
しかし、
- Glueのprojectionには
あらかじめaccountidの候補値が登録されている必要がある - 新しいaccountidが増えると
クエリで参照できない
という問題に直面しました。
調べたこと(技術的背景)
Glueのprojectionは
- 「存在しうるpartitionの値」をメタデータとして定義しておく仕組み
- 動的にS3をスキャンして自動で増えるわけではない
という仕様でした。
つまり、
S3にデータがあっても
Glueが知らないpartitionは
Athenaから参照できない
という構造です。
どう判断したか(設計)
Step Functionsの最初のステップで、
- Glueテーブルに登録されている
accountidを取得 - S3側に存在する
accountidを取得 - 差分があれば Glueに登録
という処理を追加しました。
これにより、
- 新しいaccountidが追加されても自動でGlue側に反映される
- 全アカウントについてのログを取得するAthenaクエリが成功する
という構成になりました。
まとめ
- Athenaの非同期性
- Step Functionsのデータ制限
- Glue projectionの仕組み
は表面的に使っているだけでは気づきにくい部分でした。
同じように
- AWSは触ったことがある
- でもStep FunctionsやAthenaはよく分からない
という方の参考になれば嬉しいです。
使用技術
- AWS Step Functions
- AWS Lambda
- Amazon Athena
- AWS Glue
- Amazon S3
- Amazon EventBridge