CloudWatch Logs Insights のクエリがスキャン量に影響するか確認してみた
リテールアプリ共創部@大阪の岩田です。
CloudWatch Logs Insights のクエリを実行すると、スキャンしたデータに対して課金が発生します。東京リージョンの場合、本ブログ執筆時点の2024年8月だとスキャンしたデータ 1 GB あたり USD 0.0076の課金となっています。
課金形態が類似しているAthenaの場合は、スキャン量を減らすためにデータの圧縮、パーテイション化、列指向形式への変換が有効であることが知られています。例えば列指向であるParquet形式のファイルをS3に保存している場合、クエリをSELECT * FROM table1
ではなくSELECT id FROM table1
にすることでスキャン量を抑えて課金を減らすことができます。
CloudWatch Logs Insights のストレージレイヤに関してはどのような形式でデータを保存しているのか特に情報が見つからなかったので、実際にいくつかのパターンでクエリを実行しながらクエリの修正によってスキャン量が減るのかを検証してみます。
やってみる
実際にいくつかのパターンで CloudWatch Logs Insights のクエリを実行してみます。
以後のクエリは全て同一のロググループとに対して同じ時間範囲を指定していきます。
まずは愚直に全フィールド取得
まずはマネコンを開いた時にデフォルトで表示される以下のクエリから試してみます。
fields @timestamp, @message, @logStream, @log
結果は以下の通りでした。
1,098 レコード (143.6 KB) が 4.9s @ 225 records/s (29.4 KB/s) でスキャンされました
Limitを付けてみる
次はLimitを付けてみます。特にsortは付与していないので、100レコード読みこんだ段階で処理が終了してスキャン量が減らせるかも??
fields @timestamp, @message, @logStream, @log
| limit 100
結果は以下の通りでした。
1,098 レコード (143.6 KB) が 3.3s @ 335 records/s (43.9 KB/s) でスキャンされました
1,098 レコード (143.6 KB)がスキャンされており、特にスキャン量が減ったということはありません。
フィールドを絞ってみる
次は取得対象のフィールドを絞ってみましょう。対象を@timestampだけにすればログの本体にはアクセス不要になるのでスキャン量を減らせそうな気がします。
fields @timestamp
結果は以下の通りでした。
1,098 レコード (143.6 KB) が 4.9s @ 225 records/s (29.5 KB/s) でスキャンされました
フィールドを絞ってもスキャン量は減っていません。少なくとも列指向のストレージにログが保存されているという訳では無さそうですね。
CW Logs のマネコン等からログが見えるようになってから CW Logs Insightsでログがクエリ可能になるまでの間に若干のタイムラグがあるので、保存されたログが CW Logs Insights用の列指向ストレージにレプリケートされてたりしないかな?とちょっと期待していたんですが、そんなことは無さそうですね
フィルタしてみる
次はfilterコマンドを追加してフィルタしてみましょう。
filter @message like /INIT_START/
|fields @message
結果は以下の通りでした。
1,098 レコード (143.6 KB) が 2.9s @ 382 records/s (50.0 KB/s) でスキャンされました
これもスキャン量に変更なしですね。
@timestampでフィルタしてみる
@timestampでフィルタしてみるとどうでしょうか?検索対象の時間範囲を指定するのと同義になるはずなので、スキャン量を減らせるかも??
filter @timestamp < 1723802397724
| fields @message
スキャン量は以下の通りでした
1,098 レコード (143.6 KB) が 2.8s @ 398 records/s (52.1 KB/s) でスキャンされました
抽出されるレコード数は減ったのですが、特にスキャン量は減りませんでした。@timestampによるフィルタは検索対象の時間範囲指定と同じ振る舞いにはならないみたいですね。
ログストリームの一意な値の数を集計する
以下のクエリはどうでしょうか?
stats count_distinct(@logStream)
対象期間に含まれるログストリームの一意な値の数を集計するクエリです。
AWS CLIで考えるとdescribe-log-streams
の結果に含まれるLogStreamの数をカウントするだけで集計可能な情報です。
もしCW Logs Insightsのバックエンドにオプティマイザ的なものが存在すればスキャン量が減らせても良さそうなクエリです。
結果は以下の通りでした。
1,098 レコード (143.6 KB) が 2.7s @ 410 records/s (53.7 KB/s) でスキャンされました
愚直に全レコードをスキャンして集計してそうですね
まとめ
検証の結果CloudWatch Logs Insightsではクエリの中身を見直してもスキャン量は減らなさそうということが分かりました。公式ドキュメントにも以下のように記載されており、クエリの書き方を工夫することでスキャン量が最適化できるという記述は見つかりませんでした。
To avoid incurring excessive charges by running large queries, keep in mind the following best practices:
- Select only the necessary log groups for each query.
- Always specify the narrowest possible time range for your queries.
- When you use the console to run queries, cancel all your queries before you close the CloudWatch Logs Insights console page. Otherwise, queries continue to run until completion.
- When you add a CloudWatch Logs Insights widget to a dashboard, ensure that the dashboard is not refreshing at a high frequency, because each refresh starts a new query.
CW Logs Insightsの課金を最適化するにはロググループと検索対象の時間範囲指定を最小化すること、間違ってスキャンを開始してしまった場合はできる限り早くキャンセルすることが重要と言えそうです。