Udemy講師クーポン配布中。詳しくはこちら

CloudWatchアラームがLambdaのエラーを検知しない原因と対策【見逃し防止】

CloudWatchアラームがLambdaのエラーを検知しない原因と対策【見逃し防止】アイキャッチ

運用中のシステムで、Lambdaがエラーになっているのに、CloudWatchアラームが発報されなくて困ったことはありませんか?

私自身、数ヶ月前のある日、通常のシステム運用作業中にたまたまLambdaのエラーログを発見したことがきっかけでした。よく見ると、その関数は異常終了していました。

「おかしい。LambdaのErrorsメトリクスに対してCloudWatchアラームを設定してあるはず。エラーがあれば監視チームにアラートメールが飛ぶはずなのに、なぜ誰も気づかなかったのか?」

かなりの時間をかけてAWSドキュメントを調査した結果、見落としていたLambdaメトリクスの仕様にたどり着きました。同じ問題で悩んでいる人の助けになればと思い、この記事にまとめます。


目次

発生した事象

状況

  • Lambda関数でエラーが発生(異常終了)
  • Errorsメトリクスを監視するCloudWatchアラームを設定済み
  • しきい値超えにもかかわらず、アラートメールが送信されなかった
  • 事後にCloudWatchコンソールで確認すると、該当時間帯にErrors=3が記録されていた

Lambdaの実行ログ

START RequestId: a3f291bc-4e17-48c2-9d1a-7b3e85f21c04  09:32:15
[ERROR] WaiterError: Waiter InstanceStatusOk failed: Max attempts exceeded
END RequestId: a3f291bc-4e17-48c2-9d1a-7b3e85f21c04   09:41:47
REPORT RequestId: a3f291bc-4e17-48c2-9d1a-7b3e85f21c04 Duration: 572431.18 ms  Billed Duration: 572432 ms  Memory Size: 512 MB  Max Memory Used: 88 MB

ポイントは Duration が約572秒(約9分32秒) という点です。関数が呼び出されてからエラーが発生するまでに、約9分半の時間差があります。


原因:LambdaのErrorsメトリクスのタイムスタンプ仕様

CloudWatchアラームが検知しない根本原因

ここが今回の核心です。AWSの公式ドキュメントには以下のように記載されています。

エラーメトリクスのタイムスタンプは、エラーが発生した時点ではなく、関数が呼び出された時間を反映していることに注意してください。

呼び出しメトリクス | AWS Lambda

つまり Errors メトリクスのタイムスタンプは、エラーが起きた時刻ではなく、Lambdaが呼び出された時刻になります。多くのエンジニアが「エラーが起きた時刻に記録される」と思い込んでいるため、CloudWatchアラーム 検知しないという問題の見落としにつながります。

今回のタイムラインで整理する

09:32:15  Lambda 呼び出し
          ↓ ← Errorsメトリクスのタイムスタンプはここ(09:32のバケット)
          EC2 の InstanceStatusOk を約9分半ポーリング
          ↓
09:41:47  WaiterError 発生(エラー)
          ↓ ← 実際にエラーが起きた時刻

アラームの設定が「期間:1分 / データポイント:1/1」の場合、アラームは常に直近1分間のデータのみ評価します。

時刻 メトリクスの状態 アラームの動き
09:32〜09:33 Errors=3 が記録(呼び出し時刻) 評価時は値なし
09:41〜09:42 値なし(エラー発生時刻付近) 評価 → 値なし → 発報されない

エラーが発生する09:41ごろにアラームが評価を行った際、Errors=3 のデータは 09:32のバケットにあり、評価ウィンドウの外に出ていました。結果として、アラームはしきい値超えを検知できませんでした。

なぜ後からメトリクスを見ると値があるのか

CloudWatchコンソールで「期間:1時間 / 統計:合計」で確認すると、09:32のデータポイントも集計されるためErrors=3が見えます。しかしアラームは1分単位の直近ウィンドウしか評価していないため、「メトリクスはある、でもアラームは鳴らなかった」という一見矛盾した状態が発生します。


根本原因:Lambda側のエラー内容

今回のエラーの正体は WaiterError: Waiter InstanceStatusOk failed: Max attempts exceeded でした。

# 該当コード(抜粋)
waiter = ec2_client.get_waiter('instance_status_ok')
waiter.wait(InstanceIds=[instance_id])

boto3 の InstanceStatusOk ウェイターはデフォルトで 40回 × 15秒間隔 = 最大10分 ポーリングします。対象のEC2インスタンスが期待どおりの状態にならなかったため、上限近くまで待ち続けてからエラーになりました。

この「呼び出しからエラー発生まで約9分半」という処理時間が、CloudWatchアラームの評価期間(1分)を大幅に上回っていたことが、Lambda エラー 検知されない直接的な要因です。


対策

対策① CloudWatchアラームの評価期間を延ばす(最重要)

Lambda関数のタイムアウト設定時間を基準に、アラームの評価期間を設定するのがポイントです。

ルール:アラームの評価期間 ≥ Lambdaのタイムアウト時間

設定項目 変更前 変更後(例)
期間(Period) 1分 10分
データポイント数(Datapoints to Alarm) 1/1 1/10
しきい値 1以上 1以上(変更なし)

CloudWatch コンソールでの設定例:

期間: 600秒(10分)
統計: 合計(Sum)
しきい値タイプ: 静的
条件: 1 以上
評価期間: 10

対策② boto3ウェイターの待機時間を短縮する

ウェイターの最大待機時間を短くすることで、エラー発生までの時間を予測しやすくなります。

import boto3

waiter = ec2_client.get_waiter('instance_status_ok')
waiter.wait(
    InstanceIds=[instance_id],
    WaiterConfig={
        'Delay': 15,       # ポーリング間隔(秒)
        'MaxAttempts': 10  # 最大試行回数 → 最大2分30秒
    }
)

待機時間を短くすることで、アラームの評価期間とのズレも小さくなります。

対策③ Lambdaのタイムアウト設定を見直す

処理時間が長い関数は、Lambda関数のタイムアウト値も明示的に設定し、タイムアウト時間 ≒ アラームの評価期間になるよう合わせることを意識しましょう。これにより「呼び出し〜エラーまでの最大時間」が予測しやすくなります。


まとめ

項目 内容
原因 Errorsメトリクスのタイムスタンプ=呼び出し時刻(エラー発生時刻ではない)
発生条件 呼び出しからエラー発生までの時間 > アラームの評価期間
対策① アラームの評価期間をLambdaタイムアウト以上に設定する
対策② boto3ウェイターのMaxAttemptsを小さくして待機時間を短縮する
対策③ Lambdaタイムアウト設定を明示し、アラーム期間と合わせる

CloudWatchのアラーム設定では「評価期間を短くするほど検知が速くなる」と思いがちですが、Lambda Errorsメトリクスに関しては処理時間が長いほど評価期間も長く設定する必要があるという、直感に反する設計が求められます。

今回の私のケースは数ヶ月後にたまたま発覚しましたが、これはシステムの信頼性に関わる重大な見落としです。CloudWatchアラーム 設定 が完了していても、Lambda関数の実行時間とアラームの評価期間のバランスを必ず確認するようにしましょう。

この記事がお役に立ちましたら、コーヒー1杯分(300円)の応援をいただけると嬉しいです。いただいた支援は、より良い記事作成のための時間確保や情報収集に活用させていただきます。


参考リンク

ランキング

ランキングに参加しています。クリックして応援いただけると嬉しいです。
にほんブログ村 IT技術ブログ クラウドコンピューティングへ
にほんブログ村
AWSランキング
AWSランキング

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次