はじめに
最近何かとお世話になっている、CloudWatch Logs Insights
RDBMSがバックエンドのシステムで平常時には問題なく動いているが、高負荷・数百Req/Sec等の世界になると
単なるカウントアップ/集計ロジックがアプリケーションの正常な動作を阻害してしまう等もよくある話と思います。
そんな場合には、アーキテクチャの変更も必要となると思いますが
無理にスケールアップ等で乗り切ろうとせずに、リアルタイム性はそこそこに、思い切ってバッチ処理に切り替え
LogsInsights等を利用しログから集計してみませんかというご提案です。
目次
- 前提条件
- パターン1 生データ表示
- パターン2 JSONパースを実施
- パターン3 filter で特定値を含むログを絞り込み
- パターン4 いよいよ集計処理
- パターン5 集計処理でSUM
- API経由で情報を取得
- まとめ
前提条件
集計したいログを、JSON形式でロギングしましょう。
今回は下記のようなログを用意してみました。
- userID ユーザID
- shopID 店舗ID
- price (お買い物?)価格
パターン1 生データ表示
まずはLogs Insightsで対象のロググループを選択し、用意されているクエリを実行してみます。
sort、limit についてはSQLライクに、@message がLogsに発行されたログとなります。
パターン2 JSONパースを実施
発行されたJSONログをパースしてみます。
キー名を並べればそのままパースしてくれ、ネストされていても キー名.キー名 と記載可能です。
パターン3 filter で特定値を含むログを絞り込み
集計対象とするログをFilterlingする事が可能です、SQLのWHERE句のような書き方ですね
イコール以外、正規表現マッチングも可能です。
パターン4 いよいよ集計処理
いよいよ集計処理を実施してみます
| stats count(*) by shopID
無理やりSQLに置き換えるならば count(*) from ... group by shopID という感じですね。
shopID毎の行数集計ということで、買い物が実施された回数をカウントしています。
パターン5 集計処理でSUM
| stats sum(price) by shopID
無理やりSQLに置き換えるならば sum(price) from ... group by shopID という感じですね。
shopID毎の行数集計ということで、店舗毎の売上を算出しています。
API経由で情報を取得
実行対象のロググループ、実行時間、クエリを指定することで、実行結果取得用IDが返却されます。
$ aws logs start-query \ --log-group-name '/test/log' \ --start-time 1625721144 \ --end-time 1625731144 \ --query-string 'fields @timestamp, userID, shopID, price | stats sum(price) by userID | sort by userID' クエリ実行結果 { "queryId": "6110a423-15b3-45e2-8477-ae664bdce615" }
実行結果のIDを元に下記コマンドを実行します
$ aws logs get-query-results \ --query-id '6110a423-15b3-45e2-8477-ae664bdce615'
結果取得
実際にはAPIで同様のオペレーションを実施し結果取得、JSONDecode/Parseし何らか加工するという流れになると思います。
実際に取得した結果は下記となります。
まとめ
CloudWatch LogsInsightsはちょこちょことUpdateが実施されており、こちらに記載した単純なパターン以外にも、特定フィールドを対象に distinct, min, max 等の結果を出す事も可能です。
2021/7/20追記
ただし、下記リンク先にも記載がありますが count_distinct においては下記記載がありますので要注意です。
フィールドの一意な値の数を返します。このフィールドの濃度が非常に高い場合 (一意な値が多数含まれている場合)、count_distinct から返される値は単なる概算値です。
数値処理関数、文字列関数等もSQLLikeな物が用意されており、SQLを書いたことがあればとっつきやすいサービスです。
集計結果をCloudWatch Dashboardに表示しておくだけでも、アプリケーション内部の動作がピンポイントで色々表現出来ますね。
CloudWatch Logs Insights のクエリ構文
とても便利なLogsInsightsですが、取得出来る結果の最大数は現時点で 10,000件 となっている事や
ログ件数が大量になった場合には実行時間は伸びていく傾向にありますので、その点に注意をしつつ活用する事で非常に有用なサービスだと思います。
※実案件で利用しているものですと、20万件程のログで9秒という結果だったため、バッチ実行としては全く問題無いパフォーマンスが出るサービスと考えています。