Lambda 関数の同時実行数を超えた呼び出しでスロットリングエラーが発生したことを確認する方法
困っていた内容
Lambda のイベントソースとして SQS を利用しましたが、Lambda 関数の同時実行数を 1 すると、 稀にスロットリングエラーが発生します。
スロットリングエラーが発生した際に、Lambda 関数から出力されたログが、CloudWatch Logs に出力されておりません。 Lambda 関数の呼び出しに対するスロットリングエラーを確認する方法を教えてください。
どう対応すればいいの?
Lambda 関数を呼び出した際にスロットリングが発生した場合は、CloudWatch の Throttles メトリクスに値が記録されます。
ただし、Lambda 関数の実行ログにはスロットリングによる情報は記録されません。
Throttles – スロットリングされた呼び出しリクエストの数。すべての関数インスタンスがリクエストを処理していて、スケールアップできる同時実行がない場合、Lambda は TooManyRequestsException を使用して追加のリクエストを拒否します。スロットリングされたリクエストやその他の呼び出しエラーは、Invocations または Errors としてカウントされません。
AWS Lambda 関数メトリクスの使用 - AWS Lambda
Lambda 関数の実行ログは、Lambda 関数が呼び出され関数コードが実行された場合に記録されます。
そのため、スロットリングが発生した場合には、関数コードは実行されませんため、実行ログは記録されないものとなります。
やってみた
以下のような構成で、SQS の FIFO キューに対して多くのリクエスト負荷をかけてみます。
大量のリクエストを一気に送って Lambda を同時にたくさん起動させてスロットリングエラーを意図的に発生させます。 Lambda の前段には、FIFO キューの SQS を配置して同期的に Lambda を起動します。 一方、API Gateway のバックエンドに SQS を配置し、API Gateway に対して大量のリクエストを発行して、SQS へ大量のキューを送ります。
リクエストは、手動だと大変なのでシェルスクリプトで curl を何千回もループするように記述して、プログラム上で実行します。
シェルスクリプトは以下のような処理内容で実行します なお、毎回異なるメッセージを発行するために、シェルの組み込み変数である$RANDOM 変数を使って乱数を生成します。
- curl_post_queue_loop.sh
#!/bin/bash URL=https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/test/enqueue #API Gateway のエンドポイントURL HEAD="Content-Type:application/json" #ヘッダー for i in {1..5000} do curl -X POST "${URL}?MessageGroupId=nakano${RANDOM}" -H $HEAD -d"{ \"num\": \"${RANDOM} }" done
一方で、Lambda 関数は以下の様な処理を Node.js で記述します。Lambda が起動して処理されると、CloudWatch Logs に SQS へ届いてたメッセージ内容を記録するようにします。
- index.js
exports.handler = async function(event, context) { event.Records.forEach(record => { const { body } = record; console.log(body); }); return {}; }
その他、API Gateway と SQS の設定は以下のブログを参考に設定します。
ローカル PC に作成した、シェルスクリプトを実行してみます。
$ sh curl_post_queue_loop.sh
最初は、Lambda が起動して処理してくれますが、同時実行数の制限を超えると Lambda は起動せずにスロットリングエラーを生成します。 該当の CloudWatch を確認すると、以下の様に Throttles が スパイクしていることが確認できます。 また、スロットリングエラーが発生すると、Invocations のメトリクスは一定となり Lambda 起動のスケーリングが抑えられていることがわかります。
一方で、Lambda がストットリングされた場合は、Errors のメトリクスには Lambda のエラーが記録されません。 これは、以下のドキュメントにも記載されている通り、スロットリングされた場合、実行された Lambda の処理に対してエラーが発生するわけではないので、 Errors のメトリクスには何も記録されません。
スロットリングされたリクエストやその他の呼び出しエラーは、Invocations または Errors としてカウントされません。
AWS Lambda 関数メトリクスの使用 - AWS Lambda