[アップデート] 複数のリソースのメトリクスに対してまとめてアラーム設定ができるAmazon CloudWatch Metrics Insightsアラームが使えるようになりました

リソースだけ異なるCloudWatchアラームを大量に作成することがなくなりそう
2022.12.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

複数のリソースのメトリクスに対してまとめてCloudWatchアラームの設定をしたいな

こんにちは、のんピ(@non____97)です。

皆さんは複数のリソースのメトリクスに対してまとめてCloudWatchアラームの設定をしたいなと思ったことはありますか? 私はあります。

CloudWatchアラームはトリガーする基準となるメトリクスを複数選択することはできません。

そのため、EC2インスタンスが大量にあるとEC2インスタンス毎にCPU使用率監視用CloudWatchアラーム、メモリ使用率監視用CloudWatchアラーム、ディスク使用率監視用CloudWatchアラーム... と「EC2インスタンスの数 × メトリクスの数」分設定・管理することになり、かなり大変です。

そんな折、Amazon CloudWatch Metrics Insightsアラームなる機能が発表されました。

CloudWatch Metrics Insightsの説明は以下記事をご覧ください。

これにより、「メモリ使用率が閾値超えているEC2インスタンスが1つでもあったら通知する」といったことができそうです。

早速試してみたので紹介します。

いきなりまとめ

  • 複数のリソースのメトリクスに対してまとめてアラーム設定ができる
    • 各リソースのメトリクス毎にCloudWatchアラームを設定する必要がなくなる
  • CloudWatch Metrics InsightsのSQLのWHERE句で対象リソースを絞り込んだり、除外することも可能
  • 1つのリソースでもメトリクスが閾値を超えたらアラーム状態になる
  • アラーム状態を検知したら、GROUP BYで対象リソースを絞り込む運用になりそう

やってみた

CloudWatchアラームの作成

複数あるEC2インスタンスのいずれかのCPU使用率が30%を超過したら、SNSトピックに通知するようなCloudWatchアラームを設定します。

CloudWatchのコンソールからすべてのアラーム-アラームの作成をクリックします。

アラームの作成

メトリクスの選択をクリックします。

メトリクスの選択

インスタンス別のCPU使用率の最大値を取得するようにCloudWatch Metrics Insightsでクエリを定義します。その後、実行をして意図したグラフが表示されることを確認してメトリクスの選択をクリックします。

Metrics Insights - Query Builder

こちらのクエリは以下の通りです。

SELECT MAX(CPUUtilization) FROM SCHEMA("AWS/EC2", InstanceId)

なお、GROUP BYを付与したアラームを作成しようとすると以下のメッセージと共に怒られます。「複数のメトリクスのいずれかが閾値を超えたら」ということはできないようです。

GROUP BY ステートメントを含むメトリックスクエリではアラームを作成できません。アラームの詳細はこちらを参照ください。
To produce a single time series, you can try using one of these math functions: AVG, MIN, MAX, FIRST, LAST. Learn more about math functions.

GROUP BYのアラームは設定できない

メトリクスの選択をしたら、次に条件を設定します。今回はCPU使用率が30%以上とします。

メトリクスと条件の指定

次にアクションの設定です。アラーム状態になったら事前に作成していたSNSトピックに通知するよう設定します。

アクションの設定

名前と説明を適当に入力して次へをクリックします。

名前と説明を追加

作成されるCloudWatchアラームを確認してアラームの作成をクリックします。

プレビューと作成

作成したCloudWatchアラームを確認します。状態はOKとなっていますね。

作成したCloudWatchアラームの確認

こちらのCloudWatchアラームのCloudFormationの定義は以下のようになります。

Type: AWS::CloudWatch::Alarm
Properties:
    AlarmName: cpu-alarm
    AlarmDescription: |-
        # 説明

        これは us-east-1 のいずれかのEC2インスタンスのCPU使用率が閾値を超えたときに通知するアラームです。
    ActionsEnabled: true
    OKActions: []
    AlarmActions:
        - arn:aws:sns:us-east-1:<AWSアカウントID>:LaunchWizardStack-TopicBFC7AF6E-QH7HCZW0RHO4
    InsufficientDataActions: []
    Dimensions: []
    EvaluationPeriods: 1
    DatapointsToAlarm: 1
    Threshold: 30
    ComparisonOperator: GreaterThanOrEqualToThreshold
    TreatMissingData: missing
    Metrics:
        - Id: q1
          Label: "[max: ${MAX}] "
          ReturnData: true
          Expression: SELECT MAX(CPUUtilization) FROM SCHEMA("AWS/EC2", InstanceId)
          Period: 60

AWS CLIで作成する場合は以下の通りです。

aws cloudwatch put-metric-alarm \
    --alarm-name 'cpu-alarm' \
    --alarm-description '# 説明
    
    これは us-east-1 のいずれかのEC2インスタンスのCPU使用率が閾値を超えたときに通知するアラームです。' \
    --actions-enabled \
    --alarm-actions 'arn:aws:sns:us-east-1:<AWSアカウントID>:LaunchWizardStack-TopicBFC7AF6E-QH7HCZW0RHO4' \
    --evaluation-periods 1 \
    --datapoints-to-alarm 1 \
    --threshold 30 \
    --comparison-operator 'GreaterThanOrEqualToThreshold' \
    --treat-missing-data 'missing' \
    --metrics '[{"Id":"q1","Label":"[max: ${MAX}] ","ReturnData":true,"Expression":"SELECT MAX(CPUUtilization) FROM SCHEMA(\"AWS/EC2\", InstanceId)","Period":60}]'

1台だけEC2インスタンスのCPU使用率を100%にして通知されるか確認

それではEC2インスタンスを1台だけCPU使用率を100%にしてみます。

すると状態がアラーム状態になりました。CloudWatchアラームを1つしか設定していないのに、これは嬉しい。

アラーム状態になったことを確認

アラーム状態になったため、以下メールも通知されました。メールのフォーマットがなんだか進化している気がします。

You are receiving this email because your Amazon CloudWatch Alarm "cpu-alarm" in the US East (N. Virginia) region has entered the ALARM state, because "Threshold Crossed: 1 out of the last 1 datapoints [70.43450724178736 (15/12/22 02:18:00)] was greater than or equal to the threshold (30.0) (minimum 1 datapoint for OK -> ALARM transition)." at "Thursday 15 December, 2022 02:19:16 UTC".

View this alarm in the AWS Management Console:
https://us-east-1.console.aws.amazon.com/cloudwatch/deeplink.js?region=us-east-1#alarmsV2:alarm/cpu-alarm

Alarm Details:
- Name:                       cpu-alarm
- Description:                # 説明

これは us-east-1 のいずれかのEC2インスタンスのCPU使用率が閾値を超えたときに通知するアラームです。
- State Change:               OK -> ALARM
- Reason for State Change:    Threshold Crossed: 1 out of the last 1 datapoints [70.43450724178736 (15/12/22 02:18:00)] was greater than or equal to the threshold (30.0) (minimum 1 datapoint for OK -> ALARM transition).
- Timestamp:                  Thursday 15 December, 2022 02:19:16 UTC
- AWS Account:                <AWSアカウントID>
- Alarm Arn:                  arn:aws:cloudwatch:us-east-1:<AWSアカウントID>:alarm:cpu-alarm

Threshold:
- The alarm is in the ALARM state when the metric is GreaterThanOrEqualToThreshold 30.0 for at least 1 of the last 1 period(s) of 60 seconds.



Monitored Metrics:
- MetricExpression:           SELECT MAX(CPUUtilization) FROM SCHEMA("AWS/EC2", InstanceId)
- MetricLabel:                [max: ${MAX}]

State Change Actions:
- OK:
- ALARM: [arn:aws:sns:us-east-1:<AWSアカウントID>:LaunchWizardStack-TopicBFC7AF6E-QH7HCZW0RHO4]
- INSUFFICIENT_DATA:

そのまましばらく待つと、状態がOKになり、その1分後にアラーム状態になっていました。表示されるメトリクスを見ても常に閾値は超えているので不思議です。

アラーム状態に2度遷移している

そのままさらに待つと、また状態がOKになり、その1分後にアラーム状態になっていました。不思議です。

3度目の遷移

メトリクスで表示をクリックして、GROUP BYInstanceIdを指定しても、対象のEC2インスタンスのCPU使用率は常に閾値を超えているようです。

GROUP BYを指定

これは謎ですね。

アラーム状態中に2台目のEC2インスタンスのCPU使用率も100%にした場合通知されるか

アラーム状態中に2台目のEC2インスタンスのCPU使用率も100%にした場合に通知されるか確認してみます。

既にアラーム状態なので状態遷移は発生せず、通知は行われないとは思いますが念の為確認です。

2台目のEC2インスタンスのCPU使用率を100%にしてみます。

2台とも閾値を超えたことを確認

この時のCloudWatchアラームを確認します。

アラーム状態は変わらず

アラーム状態のままで追加のアクションも発生していないようです。

当然ですが通知メールも届いていませんでした。

一度全EC2インスタンスのCPU使用率を閾値以下にしてから再度100%にした場合

メトリクスが常に閾値を超えているのにも関わらず状態がOKに遷移するのがどうしても解せないので、一度全EC2インスタンスのCPU使用率を閾値以下にしてから再度100%にして、状態がどのように遷移するのか確認します。

一度全EC2インスタンスのCPU使用率を閾値以下にしてから再度CPU使用率を100%にしてみました。

1時間ほど放置すると、常に閾値を超えているのにも関わらず状態がアラーム状態からOKへ4回遷移していました。

OKに4度遷移している

該当時間帯のメトリクスの最小値を確認しましたが、CPU使用率を100%にしているEC2インスタンスの最小のCPU使用率は92.15でした。不思議です。

該当時間帯のメトリクスの最小値を確認

EBSボリュームへの書き込み操作数のCloudWatchアラームで再チャレンジ

CPU使用率のみ、このような事象が発生するのかな?と思い他のメトリクスでも試してみます。

EC2インスタンスに接続された全EBSボリュームからの完了した書き込み操作のメトリクスであるEBSWriteOpsで試します。

EBSWriteOpsの1分間の最大値が300以上になった場合にアラーム状態になるように、CloudWatchアラームを設定します。

EBSWriteOps-alarm

CloudWatchアラームの設定後、以下スクリプトでEBSボリュームに大量に書き込みしてみます。

while sleep 1; do
  sudo dd if=/dev/urandom of=/home/ssm-user/testfile_1 bs=1K count=1048576
done

書き込みをして程なくして、状態がアラーム状態になりました。そのまま30分程放置しましたが、状態がOKになることはありませんでした。

アラーム状態から遷移していないことを確認

各EC2インスタンスのEBSWriteOpsは以下の通りです。1台のみ閾値超えていることが分かりますね。

1台のEC2インスタンスのみ閾値を超えていることを確認

OKに遷移してしまう事象が発生するのはCPU使用率(CPUUtilization)のみなのでしょうか。謎が謎を呼びます。

2022/12/30 : 追記ここから

色々調べていると原因はCloudWatchアラームの評価タイミングにCloudWatchメトリクスのデータポイントの反映が遅れていたということが分かりました。

CloudWatchアラームの評価は、当然ですが参照可能なデータポイントを使用してアラームの状態の評価を行います。また、データポイントの反映が遅れていたとしても、そのデータポイントの反映を待たずに評価を行います。

今回の場合はCPU使用率を100%にしてEC2インスタンスの負荷が高い状態になっています。加えて、アラームを実行するデータポイントはを1/1としています。そのため、CPU使用率の高いEC2インスタンスのデータポイントの反映がCloudWatchアラームの評価タイミングに一瞬でも遅れてしまうと、今回の事象のようにCPU使用率を高負荷にしていないEC2インスタンスのCPU使用率(CPUUtilization)が最大値となってしまい、条件を満たしていないと判定されて一時的にOKになってしまいます。

このようなデータポイントの反映遅延によるアラームの意図しない状態変化の回避策は、アラームを実行するデータポイントを「1/2」や「2/3」など分母と分子の数が一致しないようにすることが挙げられます。

アラームを実行するデータポイントの分母と分子の数が一致しているような定義だと、アラーム状態になるにはデータポイントが分母の数分連続して条件を満たす必要があります。裏を返せば1データポイントでも条件を満たさなければ状態がOKとなってしまいます。いわゆるフォールスネガティブにはなりにくいですが、フォールスポジティブとなりやすい状態でもあります。

アラームを実行するデータポイントを「1/2」や「1/3」、「2/3」など分母と分子の数が一致しないようにすることで、複数のデータポイント(分母)のうち、データポイントが一定数(分子)条件を満たすときにアラーム状態になります。逆にOKになるには条件を満たさないようなデータポイントが一定数必要になります。

例) アラームを実行するデータポイント毎のOKになるために必要な条件を満たさないデータポイントの数

  • 「1/2」 : 2データポイントの内2データポイント
  • 「1/3」 : 3データポイントの内3データポイント
  • 「2/3」 : 3データポイントの内2データポイント

2022/12/30 : 追記ここまで

リソースだけ異なるCloudWatchアラームを大量に作成することがなくなりそう

複数のリソースのメトリクスに対してまとめてアラーム設定ができるAmazon CloudWatch Metrics Insightsアラームが使えるようになったアップデートを紹介しました。

これにより、リソースだけ異なるCloudWatchアラームを大量に作成することがなくなりそうです。

対象のリソースを絞り込み/除外したい場合は、CloudWatch Metrics InsightsのSQLのWHERE句でコントロールすることができます。個人的にはIDのみではなく、タグを使って絞り込みができると嬉しいです。

運用としては、アラーム状態を検知したら、GROUP BYで対象リソースを絞り込んで対応をするといったことになりそうです。なお、実際に検証しましたが既にアラーム状態になると他のリソースのメトリクスが閾値を超えても通知されません。そのため、アラーム状態を放置していると新規アラームに気づくことができません。アラーム状態を放置しないように運用しましょう。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!