Lambda 関数の同時実行数を超えた呼び出しでスロットリングエラーが発生したことを確認する方法

スロットリングが発生した場合は、CloudWatch の Throttles メトリクスに値が記録されます

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

困っていた内容

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 の設定は以下のブログを参考に設定します。

API GatewayからSQSのFIFOキューにメッセージをPOSTする

ローカル PC に作成した、シェルスクリプトを実行してみます。

$ sh curl_post_queue_loop.sh

最初は、Lambda が起動して処理してくれますが、同時実行数の制限を超えると Lambda は起動せずにスロットリングエラーを生成します。 該当の CloudWatch を確認すると、以下の様に Throttles が スパイクしていることが確認できます。 また、スロットリングエラーが発生すると、Invocations のメトリクスは一定となり Lambda 起動のスケーリングが抑えられていることがわかります。

一方で、Lambda がストットリングされた場合は、Errors のメトリクスには Lambda のエラーが記録されません。 これは、以下のドキュメントにも記載されている通り、スロットリングされた場合、実行された Lambda の処理に対してエラーが発生するわけではないので、 Errors のメトリクスには何も記録されません。

スロットリングされたリクエストやその他の呼び出しエラーは、Invocations または Errors としてカウントされません。

AWS Lambda 関数メトリクスの使用 - AWS Lambda

参考資料