AthenaとKinesis Data FirehoseでS3のログをクエリする
Kinesis Data FirehoseでログをS3に流し込み、Athenaでクエリする。カスタムプレフィックスを使ってパーティションを自動登録させる方法。
Athenaを使えば、インフラを一切プロビジョニングすることなく、S3に保存されたオブジェクトに対して直接SQLクエリを実行できます。Kinesis Data Firehoseでログを配信し、Athenaでクエリするという構成は、この組み合わせの典型的な使い方の一つです。

Kinesis Data Firehoseの作成
これを可能にしているのが、2019年2月に導入されたカスタムS3プレフィックス機能です。FirehoseはS3オブジェクトキーに対してApache Hive形式のプレフィックスを書き込めるようになり、そのプレフィックスを使ってAthenaのMSCK REPAIR TABLEがパーティションを自動的に作成できます。
Create delivery streamを押し、名前を入力します。


Direct PUT or other sourcesを選択します。

レコード処理の設定はスキップします。

配信先としてAmazon S3を選択します。

プレフィックスとエラープレフィックスを以下の形式で設定します。
- Prefix:
logs/!{timestamp:'year='yyyy'/month='MM'/day='dd'/hour='HH}/ - Error Prefix:
error_logs/!{timestamp:'year='yyyy'/month='MM'/day='dd'/hour='HH}/!{firehose:error-output-type}

要件に応じてBuffer sizeとBuffer intervalを調整します。

ストレージコストを削減するためGZIP圧縮を使用します。

配信ストリーム用のIAMロールを作成、または既存のものを選択します。

データのストリーミング
Kinesis Data Firehoseの配信ストリームへプログラムからデータを送るには、AWS SDK for PHP: FirehoseClient#putRecordメソッドが使えます。
$client = new FirehoseClient([ 'region' => '<AWS_REGION>', 'version' => 'latest',]);
$data = [ 'log_id' => 12345, 'url' => 'https://example.com',];
$client->putRecord([ 'DeliveryStreamName' => '<YOUR_STREAM>', 'Record' => [ 'Data' => json_encode($data) . PHP_EOL, ],]);Athenaテーブルの作成
AthenaコンソールでCreate table from S3 bucket dataを選択します。

データベース名、テーブル名、そしてFirehoseが使用しているS3パスを入力します。

データフォーマットとしてJSONを指定します。

データ構造に応じてカラムを定義します。

クエリのパフォーマンスを向上させるため、パーティション(例:year/month/day/hour)を設定します。
パーティショニングによりスキャンされるデータ量が最小限に抑えられ、コストが大幅に削減されます。

パーティションは以下のコマンドで読み込みます。

MSCK REPAIR TABLE {TABLE_NAME};Athenaテーブルへのクエリ
パーティションが設定されていれば、データセット全体をスキャンする代わりに、特定の日付範囲を対象にクエリを実行できます。
SELECT *FROM table_nameWHERE year = 2019 AND month = 8 AND day = 30LIMIT 10;ベストプラクティス:
WHERE句には必ずパーティションキーを含める。- 不要なスキャンを避けるため
LIMIT句を使用する。
まとめ
このパイプラインにより、Kinesis Data Firehose経由でログをS3に配信し、データベースのインフラを一切プロビジョニングすることなくAthenaでクエリ可能な状態にすることができました。ここでポイントになるのがカスタムS3プレフィックス機能です。year=/month=/day=/hour=というプレフィックスの下にオブジェクトを書き込むことで、ログが1時間増えるたびにALTER TABLE ... ADD PARTITIONを実行する必要がなくなり、MSCK REPAIR TABLEがパーティションを自ら発見して登録できるようになります。Firehoseの配信ストリームにおけるGZIP圧縮と、WHERE句によるパーティションプルーニングは相互に作用してストレージとクエリごとのスキャンコストの両方を抑えてくれます。Athenaはスキャンしたバイト数に応じて課金されるため、これが直接コストに響いてきます。データ量が増えるにつれて調整する価値があるのはFirehoseのバッファサイズと間隔で、バッファを大きくすると大量の小さなファイルではなく、より少数で大きめのS3オブジェクトが生成されます。こうしたオブジェクトのほうがAthenaのクエリは速くなる傾向にあります。
Related posts
Kinesis Firehoseの動的パーティショニングでNDJSON処理を簡素化する
Kinesis Data Firehoseが動的パーティショニングをサポートしたことで、NDJSON(改行区切りJSON)への変換のためだけにLambda関数を用意する必要がなくなりました。
AWS IoT Core における Kinesis Firehose のレコードセパレーター設定
IoT Core のトピックルールにある Firehose アクションでレコードセパレーターを設定し、S3 に改行区切りでレコードを格納する方法。
SiteWise Edge GatewayでOPC UAデータをKinesisにストリーミングする
SiteWise Edge Gatewayとカスタムのgreengrassコンポーネントを使って、OPC UAテレメトリをKinesis Data Streamsへ橋渡しします。
AWS Athena のパーティションプロジェクション
2020 年 6 月に導入された Athena のパーティションプロジェクションにより、新しいパーティションを追加するために手動で MSCK REPAIR TABLE を実行する必要がなくなります。
AWS IoT トピックペイロードによる Kinesis シャードの分離
IoT トピックのペイロードを顧客 ID ごとに異なる Kinesis シャードへルーティングし、後続処理でも顧客ごとの順序を保つ方法。
