AWS CloudFrontのアクセスログ解析をAthenaのPartitionProjectionでやってみた

こんにちは。BIGLOBE 永末です。
今回は Amazon Web Services (AWS) の小ネタです。

BIGLOBE では近年、 AWS などクラウドサービスの活用を積極的に進めています。CDN サービス(CloudFront)も AWS では簡単に導入できるため、レスポンスの高速化とオリジンサーバの負荷軽減施策として、積極的に採用しています。

CloudFront は便利ではあるのですが、そのまま使うとログの解析がたいへんです。ログがS3 上にファイルとして出力されるため、S3 からログファイルをダウンロードした後に検索などを行う必要があるからです。
そこで、BIGLOBE では簡単にログ解析できるように Athena を利用しています。数か月前に登場した Athena の新機能「Partition Projection」を使って、検索環境の構築を少しだけ楽にしました、というのが今回のお話です。

Partition Projectionとは

2020年6月に実装された Athena の新機能です。

aws.amazon.com

今までは Athena でパーティション検索をするには、あらかじめ Glue Data Catalog にパーティションを作成しておく必要がありました。Partition Projection を使えばこれが不要になります。例えばパーティションのパスが日付(YYYY/MM/DD)の場合、YYYY/MM/DD をパーティション情報として Glue テーブルを作成すれば、パーティションを自動で計算してくれます。パーティションの管理が不要になるだけでなく、検索も高速になります。

CloudFrontのログ検索に使ってみる

以前紹介した記事では、まだ Partition Projection がなかったので、バッチで Data Catalog にパーティションを追加していました。これでも動作に問題はないのですが、パーティションを作成する Lambda をメンテナンスする必要があるため、今回取っ払いました。

検索環境構築の道のりは以下のとおりです。

1. S3 のログファイルを移動

CloudFront が出力する S3 上のパスは次のようになっています。

S3://<バケット名>/プレフィックス/<Distribution ID>.YYYY-mm-dd-HH.xxxxxxxx.gz

まずこれをパーティションのパスに移動させます。こんな感じです。

S3://<バケット名>/プレフィックス/YYYY/mm/dd/HH/<Distribution ID>.yyyy-mm-DD-HH.xxxxxxxx.gz

このあたりは以前紹介した記事と同じで、Lambda で定期的に移動させます。

2. Glue データベースとテーブル作成

Glue データベースとテーブルを作成します。以下、CloudFormation のテンプレートです。

Partition Projection が関係するのはこのあたりです。

projection.enabled: 'true', 
projection.date.type: 'date',
projection.date.range: '2018/01/01/00,NOW',
projection.date.format: 'yyyy/MM/dd/HH',
projection.date.interval: '1', 
projection.date.interval.unit: 'HOURS',

projection.date.range で 2018/01/01 から現在までを指定しています。このあたりはお好みです。なお、projection.date.range を100年などすごく広い範囲にしても、クエリを投げる際にパーティションを指定すれば検索時間が遅くなることはなさそうです。
テンプレートの入力パラメータは以下のとおりです。

 CFLogBucket:CloudFront がログ出力するバケット
 BucketPrefix:ログバケットのログ出力先プレフィックス
 CFName:CloudFront 名 ※データベース名、テーブル名に利用

CFName の AllowedPattern に -(ハイフン) がないのは、- があるとクエリを投げる際に database、table名を " で囲む必要があり、面倒だからです。

3. Athena の初期設定

Athena 未使用の場合、クエリ結果を出力する S3 バケットを設定しておきます。また、クエリを投げる際にパーティションキーを指定し忘れると、全スキャンが発生して AWS 利用料がすごいことになってしまう可能性があります。対策として、スキャンの上限を入れておきます。

あとはクエリを投げるだけ。このような感じです。

SELECT * FROM <CloudFront名>_log_database.<CloudFront名>_log_table WHERE date = '2020/10/05/05'

ちなみに、パーティション指定をしないでフルスキャンすると検索がすっごい遅いです。 Hourly ではなくDaily で設定すると、フルスキャンでも速くなりました。 2レコードの検索でこれくらいの差が出ます。

 HOURS 指定:1m47s~2m13s
 DAYS 指定:2.33s

とはいえ、パーティション指定せずに検索することはあまりないとは思うので、気にしないことにしました。

最後に

というわけで、 Glue Data Catalog にパーティションを作成することなく検索できるようになりました。今までのやり方でも特に問題があったわけではないのですが、そこそこの数の AWS アカウントで CloudFront が動いていることもあり、今後のメンテナンス性を考えて Lambda をやめることにしました。
ALB のログ検索も同様に行えてすごく便利なので、どんどん Partition Projection を使っていきましょう!

以上です。



※ Amazon Web Services、AWSロゴおよびかかる資料で使用されるその他のAWS商標は、米国その他諸国における、Amazon.com, Inc.またはその関連会社の商標です。

f:id:biglobe-style:20201030141719p:plain:w1