AWS おもしろいやつ

[アップデート] AWS Lambda の再帰ループ検出機能にS3が追加されました

2024年7月10日

aws-lambda-icon

2024年7月9日、タイトル通りの件名でAWSからメールが届いた。内容としては、Lambdaの再帰ループ検出機能がアップデートされ、S3がトリガーであるLambdaの再帰ループが発生している場合においても検出してくれるようになった。実際どのように検出されるのかなど含め記事にまとめてみた。

2024年10月9日にAWS What’s Newで「Lambda と Amazon S3 間の再帰ループを検出して停止できるようになりました」と発表があり、再度検証したためご覧ください。

「サリー」です。AWSパートナー企業でエンジニアとして働いています。
お問い合わせ自己紹介

AWSの通知

AWSからの通知を掲載しておく。詳細は以下に記載している。

AWS Lambda の再帰的ループ検出の今後の変更についてお知らせいたします。

再帰ループ検出は、AWS Lambda と他のサポートされているサービス間の再帰ループを検出して終了し、設定ミスによる制御不能となったワークロードを防ぐものです。再帰ループ検出は現在、AWS Lambda、Amazon SQS、および Amazon SNS 間のループに対してサポートされています。2024 年に Lambda は再帰ループ検出のサポートを Amazon S3 に拡張する予定です。この機能の本格リリースに向けた段階的な措置として、Lambda は再帰ループ検出の動作に基本的な変更を加えます。

2024 年 7 月 8 日以降、S3 が Lambda 関数のイベントソースやトリガーではない Lambda と S3 を経由する再帰呼び出しは、約 16 回の再帰呼び出し後に検出され、終了されます。終了される再帰ループの例としては、S3 バケットにデータを保存する Lambda 関数があり、これにより SNS への通知がトリガーされ、同じ Lambda 関数がトリガーされる場合などが挙げられます。このアップデートは、再帰ループ検出がサポートされている商用リージョン (中東(アラブ首長国連邦)、アジアパシフィック(ハイデラバード)、アジアパシフィック(メルボルン)、イスラエル(テルアビブ)、カナダ(カルガリー)、欧州(スペイン)、欧州(チューリッヒ) を除く) の全てで、7 月に段階的にロールアウトされる予定です。

対応が必要な場合
Amazon S3 での意図的な再帰に依存する関数がある場合は、AWS サポート [1] に連絡し、このワークロードが中断されないよう、アカウントを再帰ループ検出からオプトアウトするようにしてください。オプトアウトが必要な各アカウントについて、サポートケースを作成し、オプトアウトが必要な地域を明記してください。

Lambda の再帰ループとは

簡単にいうと「無限にLambda関数が起動される状態」のこと。例えば、SNSをトリガーとするLambda関数でトリガーで登録していたSNSあてに通知するように誤って設定してしまった場合などが考えられる。

参考に公式ドキュメントの文言も掲載しておく。

関数を呼び出すのと同じサービスまたはリソースに出力するように Lambda 関数を設定すると、無限再帰ループが作成される可能性があります。例えば、Lambda 関数が Amazon Simple Queue Service (Amazon SQS) キューにメッセージを書き込み、その書き込まれたキューによって同じ関数が呼び出される場合があります。この呼び出しにより、関数はキューに別のメッセージを書き込み、キューによって関数が再び呼び出されます。

Lambda 再帰ループ検出を使用した無限ループの防止 - AWS Lambda

Lambda の再帰ループの何が問題か

再帰ループが発生する思わぬ課金が発生する可能性がある。

そもそもLambda の料金は安価のため数回の実行であれば微課金 or 無料で利用することができるが、Lambda関数が無限に繰り返された場合、単価が安いとはいえ高額の請求が届くことになることが想定される。

Lambda の再帰ループ検出機能とは

上述したLambdaの再帰ループ(無限繰り返し)を検出してくれる機能。具体的には、Lamdba関数がイベントをSNSまたはSQSに送信し、そのSNSまたはSQSでLamdba関数を起動するという一連の流れ(リクエストチェーン)が発生した回数を追跡してくれる。その回数が16回を超えて呼び出された場合、次のLamdba関数の呼び出しを自動的に停止し、ユーザーに通知する。通知はHealth Dashboard、メールにて通知される。

利用するには

ユーザーは特に設定する必要はなく、標準で有効化されている。「再帰ループを検出するために、Lambda は AWS X-Ray トレースヘッダーを使用」しているとドキュメントに記載されているが、X-rayを有効化する必要もないとのこと。無効化することもでき、意図した再帰ループを起こしたい場合はAWSサポートへ連絡することにより無効化することが可能。

サポートされている AWS のサービス

2024年7月9日より前は、Lamdba関数、SQS、SNS の間の再帰ループを検出していた。具体的には以下のような構成となっている場合のみサポートされており、S3やDynamoDBなど別のAWSサービスがループの一部を形成している場合、検出・停止はできなかった。

Lambda は現在、関数、Amazon SQS、Amazon SNS の間の再帰ループを検出します。Lambda は、Lambda 関数のみで構成されるループも検出します。これらの関数は、同期的に、または非同期的にお互いを呼び出す可能性があります。次の図に、Lambda が検出できるループの例を示します。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-recursion.html

※画像は https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-recursion.html より引用

アップデートにより何が変わったのか

上述のとおり、SNS、SQSにより構成されている場合のみLamdbaの再帰ループ検出をサポートしていたが、今回のアップデートでは、S3が構成に入っている場合でも検出・停止することが可能になった。

AWSからの通知には以下のような場合が例として挙げられるとの記述があった。

S3 バケットにデータを保存する Lambda 関数があり、これにより SNS への通知がトリガーされ、同じ Lambda 関数がトリガーされる場合などが挙げられます。

AWSの通知から引用

検証:実際にLamdba再帰ループを発生させてみる

Lambda → S3 → Lambda → S3 → の構成

Lambda関数で現在時刻のファイルを作成し、S3へPutする。S3イベント通知でLambda関数を呼び出す という流れで無限ループを発生させるように設定してみた。

結論から書くと、まだ東京リージョンには対応していなかったため無限にLamdba関数が実行され短時間のうちに300を超えるファイルが作成(Lamdba関数が実行)された。

AWSからの通知に「このアップデートは、再帰ループ検出がサポートされている商用リージョン の全てで、7 月に段階的にロールアウトされる予定です。」とあるため、近いうちに東京リージョンも対応されると思われる。(オレゴンリージョンにて同様の検証をしたが同じ結果)

実際に検証した結果。300以上のファイルが短時間の内に作成されているが、何も通知されず。。自分の認識が間違っているのか。。?

今度検証する

今回は再帰ループ検出が機能しなかったため今度検証することする。

【リベンジ】Lambda→S3→SNSで検証

公式からの連絡からあるとおり、Lambda→S3→SNSという構成を試してみることにする。

終了される再帰ループの例としては、S3 バケットにデータを保存する Lambda 関数があり、これにより SNS への通知がトリガーされ、同じ Lambda 関数がトリガーされる場合などが挙げられます。

上記構成で試したところ、17回Lambda関数が実行したところで無限ループが停止していた。上述のとおりではあるが、16回を超えて呼び出された場合、そのイベントの次の関数呼び出しを停止して再帰ループを中断していることがわかる。

少し間違い

正式には16回を超えて呼び出された場合にループが停止されるため、16回実行され17回目のループは発生しないと思われる。下でオブジェクト数が17となっているが恐らく誤りで1つオブジェクトが余計に作成されているため17個となっている。

同じトリガーイベントによって関数が 16 回を超えて呼び出された場合、Lambda はそのイベントの次の関数呼び出しを停止して再帰ループを中断します。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-recursion.html#invocation-recursion-responding

再帰ループが発生するとCloudWatchメトリクスで「RecursiveInvocationsDropped」というものが確認できるらしいとのことで、確認したところメトリクスが記録されていた。

CloudWatch メトリクスの RecursiveInvocationsDropped には、1 回のリクエストチェーンで関数が 16 回を超えて呼び出されたために Lambda が停止した関数の呼び出し回数が記録されます。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/invocation-recursion.html#invocation-recursion-monitoring

まとめ

Lambda→S3→Lambda→・・の流れでは再帰ループは検出されなかったため、恐らくSNSやSQSを含むLambda関数のループにS3が入った際、以前は検出されなかったが今回のアップデートで検出されるようになったと想定される。気になった方はサポートへ問い合わせてみてほしい。

-AWS, おもしろいやつ
-