初めに
LambdaとSQSの構成の時に、Lambdaが同時実行の制限で実行不可の場合について検証します。
検証
上記のSQSの設定にしております。これで、Lambdaの方の同時実行数の予約を0で実行してみます。
自分は当初パターン2の動作になるのではないのかなと思っていました。つまり、Lambdaが起動できない場合はSQSにメッセージが滞留してLambdaが起動できるまで再試行を繰り返すということです。
● パターン1
メッセージ送信 ➡ Lambda起動 ➡ 失敗 ➡ 5分経過 ➡ Lambda再起動 ➡ 失敗 ➡ DLQ移動
● パターン2
メッセージ送信 ➡ Lambda起動 ➡ 失敗 ➡ 5分経過 ➡ Lambda再起動 ➡ 失敗 ➡ Lambda再始動 ➡ 失敗 ➡ ...
検証結果
■ ApproximateAgeOfOldestMessageのメトリクス

■ NumberOfMessagesReceivedのメトリクス

この検証を開始したのは、15:23(JST)です。UTCでは06:23となります。
ApproximateAgeOfOldestMessageは、横軸が時間で縦軸がメッセージがの存在していた秒数になっております。06:23~-06:33までが0秒以外となっております。このことから、06:33までメッセージが存在していました。
NumberOfMessagesReceivedは、06:23と06:28のタイミングで山になっています。このことから5分おきにReciveMessageアクションを呼び出していることがわかります。つまり、初回のReciveMessageで失敗した後、可視性タイムアウトの待機を経てもう一度呼び出されております。
※ ApproximateAgeOfOldestMessegeやNumberOfMessagesRecivedは参考の「Amazon SQS で利用可能な CloudWatchメトリクス」に記載されています
結果
今回の検証から、Lambda の同時実行数が 0 に制限されている(=スロットリング状態)場合でも、SQS はメッセージを 可視性タイムアウト後に再配送し続けるということが分かりました。
これにより、最大受信回数(maxReceiveCount) を超えるとメッセージは DLQ に送られます。
したがって、本番環境では以下のような対応が重要になります:
- Lambda の処理時間短縮(タイムアウト・処理速度改善)
- 同時実行数制限の緩和(ReservedConcurrentExecutions)やクォータの増加申請
- maxReceiveCount や DLQ の設定見直し(再試行回数が適切か)
これらにより、スロットリングによるメッセージの損失や遅延を防ぐことができると思います。
参考
Amazon SQS で利用可能な CloudWatchメトリクス
https://docs.aws.amazon.com/ja_jp/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-available-cloudwatch-metrics.html

