使用 Lambda 遞迴迴圈偵測來防止無限迴圈 - AWS Lambda

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 Lambda 遞迴迴圈偵測來防止無限迴圈

當您將 Lambda 函數設定為輸出至調用該函數的相同服務或資源時,就可以建立無限遞迴迴圈。例如,Lambda 函數可能會將訊息寫入 Amazon Simple Queue Service (Amazon SQS) 佇列,然後調用相同的函數。此調用會導致函數將另一則訊息寫入佇列,進而再次調用函數。

非蓄意遞迴循環可能會導致意外費用向您的 收取 AWS 帳戶。迴圈也可能導致 Lambda 擴展和使用您帳戶的所有可用並行處理。為了協助降低意外迴圈的影響,Lambda 會在發生特定類型的遞迴循環後,立即偵測到這些循環。根據預設,當 Lambda 偵測到遞迴迴圈時,它會停止叫用函數並通知您。如果您的設計刻意使用遞迴模式,您可以變更函數的預設組態,以允許遞迴調用。如需更多資訊,請參閱允許 Lambda 函數在遞迴迴圈中執行

了解遞迴迴圈偵測

Lambda 中的遞迴迴圈偵測透過追蹤事件來運作。Lambda 是事件驅動型運算服務,可在特定事件發生時執行函數程式碼。例如,當項目新增至 Amazon SQS佇列或 Amazon Simple Notification Service (AmazonSNS) 主題時。Lambda 會將事件作為JSON物件傳遞至您的函數,其中包含系統狀態變更的相關資訊。當事件導致函數執行時,這稱為調用

若要偵測遞迴迴圈,Lambda 會使用 AWS X-Ray 追蹤標頭。當支援遞迴迴圈偵測的AWS 服務 將事件傳送至 Lambda 時,這些事件會自動使用中繼資料進行註解。當您的 Lambda 函數 AWS 服務 使用支援的 版本 AWS SDK將其中一個事件寫入到另一個支援的事件時,它會更新此中繼資料。更新後的中繼資料包含事件調用函數的次數計數。

注意

您不需要啟用 X-Ray 作用中追蹤,即可使用此功能。依預設,所有 AWS 客戶都會開啟遞迴迴路偵測。使用此功能無需支付任何費用。

請求鏈是由相同觸發事件引起的一系列 Lambda 調用。例如,假設 Amazon SQS佇列調用您的 Lambda 函數。然後,您的 Lambda 函數會將處理的事件傳回相同的 Amazon SQS佇列,這會再次調用您的函數。在此範例中,函數的每次調用都屬於相同的請求鏈。

如果您的函數在相同的請求鏈中被叫用約 16 次,則 Lambda 會自動停止該請求鏈中的下一個函數叫用,並通知您。如果函數設有多個觸發條件,來自其他觸發條件的調用不會受影響。

注意

即使來源佇列的重新驅動政策上的maxReceiveCount設定高於 16,Lambda 遞迴保護也不會阻止 Amazon 在偵測到遞迴循環並終止之後SQS重試訊息。當 Lambda 偵測到遞迴迴圈並捨棄後續調用時,會將 RecursiveInvocationException 傳回至事件來源映射。這會增加訊息上的receiveCount值。Lambda 會繼續重試訊息,並繼續封鎖函數叫用,直到 Amazon SQS判斷超過 maxReceiveCount ,並將訊息傳送至設定的無效字母佇列。

如果您為函數設定了故障時的目的地無效字母佇列,則 Lambda 也會將事件從已停止的調用中傳送至目的地或無效字母佇列。為函數設定目的地或無效字母佇列時,請務必不要使用函數也用作事件觸發或事件來源映射的 Amazon SNS主題或 Amazon SQS佇列。如果將事件傳送到調用函數的相同資源,則可以建立另一個遞迴迴圈。

支援的 AWS 服務 和 SDKs

Lambda 只能偵測包含某些支援 的遞迴迴圈 AWS 服務。若要偵測遞迴循環,您的函數也必須使用其中一個支援的 AWS SDKs。

支援的 AWS 服務

Lambda 目前偵測到函數、Amazon SQS、Amazon S3 和 Amazon 之間的遞迴循環SNS。Lambda 也會偵測僅由 Lambda 函數組成的迴圈,這些函數可以同步或非同步相互調用。下圖顯示 Lambda 可以偵測的一些迴圈範例:

Lambda 函數、Amazon SNS、Amazon S3 和 Amazon SQS佇列之間的遞迴迴圈圖表。

當 Amazon DynamoDB AWS 服務 等其他 構成迴圈的一部分時,Lambda 目前無法偵測並停止它。

由於 Lambda 目前只偵測到涉及 Amazon SQS、Amazon S3 和 Amazon 的遞迴迴圈SNS,因此涉及其他 的迴圈仍可能導致 Lambda 函數 AWS 服務 意外使用。

為了防止向您的 收取意外費用 AWS 帳戶,建議您設定 Amazon CloudWatch 警示,以提醒您不尋常的使用模式。例如,您可以設定 CloudWatch 來通知您 Lambda 函數並行或調用中的峰值。也可以設定帳單警示,當帳戶中的支出超過指定的閾值時通知您。或者,可以使用 AWS Cost Anomaly Detection 來提醒您不尋常的帳單模式。

支援的 AWS SDKs

若要讓 Lambda 偵測遞迴迴圈,您的函數必須使用下列其中一個SDK版本或更高版本:

執行期 最低必要 AWS SDK版本

Node.js

2.1147.0 (SDK第 2 版)

3.105.0 (SDK第 3 版)

Python

1.24.46 (boto3)

1.27.46 (botocore)

Java 8 和 Java 11

2.17.135

Java 17

2.20.81

Java 21

2.21.24

.NET

3.7.293.0

Ruby

3.134.0

PHP

3.232.0

Go

SDK V2 (使用最新版本)

某些 Lambda 執行期,例如 Python 和 Node.js,包括 的版本 AWS SDK。如果函數執行時間中包含的SDK版本低於所需的最低版本,則您可以將支援的 版本新增至SDK函數的部署套件 。您也可以使用 Lambda 層 將支援的SDK版本新增至函數。如需每個 Lambda 執行時間SDKs隨附的 清單,請參閱 Lambda 執行期

遞迴迴圈通知

當 Lambda 停止遞迴迴圈時,您會透過 AWS Health Dashboard 和電子郵件接收通知。您也可以使用 CloudWatch 指標來監控 Lambda 已停止的遞迴調用次數。

AWS Health Dashboard 通知

當 Lambda 停止遞迴調用時, 會在您的帳戶運作狀態頁面上,於開啟和最近問題 下 AWS Health Dashboard 顯示通知。請注意,在 Lambda 停止遞迴調用後,可能需要三個小時才會顯示此通知。如需在 中檢視帳戶事件的詳細資訊 AWS Health Dashboard,請參閱AWS 運作狀態使用者指南中的運作狀態儀表板 – 您的帳戶運作狀態入門AWS

電子郵件提醒

當 Lambda 第一次停止函數的遞迴調用時,會傳送電子郵件提醒給您。對於 AWS 帳戶中的每個函數,Lambda 每 24 小時最多傳送一封電子郵件。Lambda 傳送電子郵件通知後,即使 Lambda 停止函數的進一步遞迴調用,在接下來的 24 小時也不會再收到該函數的任何電子郵件。請注意,在 Lambda 停止遞迴調用後,可能需要三個小時才會收到此電子郵件提醒。

Lambda 會傳送遞迴循環電子郵件提醒給您 AWS 帳戶的主要帳戶聯絡人和替代操作聯絡人。如需有關檢視或更新帳戶中電子郵件地址的資訊,請參閱《AWS 一般參考》中的更新聯絡資訊

Amazon CloudWatch 指標

CloudWatch 指標RecursiveInvocationsDropped記錄 Lambda 因為在單一請求鏈中調用函數超過約 16 次而停止的函數調用次數。Lambda 會在停止遞迴調用時立即發出此指標。若要檢視此指標,請遵循在主控台上 CloudWatch檢視指標的指示,然後選擇指標 RecursiveInvocationsDropped

回應遞迴迴圈偵測通知

當相同的觸發事件調用函數超過約 16 次時,Lambda 會停止該事件的下一個函數調用,以中斷遞迴循環。若要防止 Lambda 已中斷的遞迴迴圈再次發生,請執行下列動作:

  • 將函數的可用並行處理降為零,這會限制所有將來的調用。

  • 移除或停用正在調用函數的觸發條件或事件來源映射。

  • 識別並修正程式碼瑕疵,將事件寫回叫用函數 AWS 的資源。當您使用變數來定義函數的事件來源和目標時,就會出現常見的缺陷來源。檢查兩個變數沒有使用相同的值。

此外,如果您 Lambda 函數的事件來源是 Amazon SQS佇列,請考慮在來源佇列上設定無效字母佇列。

注意

請確定在來源佇列上設定無效字母佇列,而不是在 Lambda 函數上。您在函數上設定的無效字母佇列用於佇列的非同步調用函數,而不是事件來源佇列。

如果事件來源是 Amazon SNS主題,請考慮為您的函數新增故障目的地

將函數的可用並行處理降為零 (主控台)
  1. 開啟 Lambda 主控台中的函數頁面

  2. 選擇 函數的名稱。

  3. 選擇調節

  4. 調節函數對話方塊中,選擇確認

若要移除函數的觸發條件或事件來源映射 (主控台)
  1. 開啟 Lambda 主控台中的函數頁面

  2. 選擇 函數的名稱。

  3. 選擇組態索引標籤,然後觸發條件

  4. 觸發條件下,選取要刪除的觸發條件或事件來源映射,然後選擇刪除

  5. 刪除觸發條件對話方塊中,選擇刪除

若要停用函數的事件來源映射 (AWS CLI)
  1. 若要尋找您要停用的事件來源映射UUID的 ,請執行 AWS Command Line Interface (AWS CLI) list-event-source-mappings命令。

    aws lambda list-event-source-mappings
  2. 若要停用事件來源映射,請執行下列 AWS CLI update-event-source-mapping命令。

    aws lambda update-event-source-mapping --function-name MyFunction \ --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --no-enabled

允許 Lambda 函數在遞迴迴圈中執行

如果您的設計刻意使用遞迴迴圈,您可以設定 Lambda 函數,以允許遞迴調用該函數。建議您避免在設計中使用遞迴迴圈。實作錯誤可能會導致使用 所有 AWS 帳戶可用的並行進行遞迴調用,以及從您的帳戶支付非預期的費用。

重要

如果您使用遞迴循環,請謹慎處理。實作最佳實務防護軌道,將實作錯誤的風險降至最低。若要進一步了解使用遞迴模式的最佳實務,請參閱 Serverless Land 中導致失效的遞迴模式

您可以設定函數,以允許使用 Lambda 主控台、 AWS Command Line Interface (AWS CLI) 和 PutFunctionRecursionConfig 進行遞迴循環API。您也可以在 AWS SAM 和 中設定函數的遞迴迴圈偵測設定 AWS CloudFormation。

根據預設,Lambda 會偵測並終止遞迴循環。除非設計刻意使用遞迴迴圈,否則建議您不要變更函數的預設組態。

請注意,當您設定函數以允許遞迴循環時,RecursiveInvocationsDropped不會發出CloudWatch 指標

Console
允許函數在遞迴迴圈 (主控台) 中執行
  1. 開啟 Lambda 主控台中的函數頁面

  2. 選擇函數的名稱以開啟函數詳細資訊頁面。

  3. 選擇組態索引標籤,然後選擇並行和遞迴偵測

  4. 除了遞迴迴圈偵測 之外,選擇編輯

  5. 選取允許遞迴循環

  6. 選擇 Save (儲存)。

AWS CLI

您可以使用 PutFunctionRecursionConfigAPI來允許在遞迴迴圈中叫用函數。Allow 指定遞迴迴圈參數。例如,您可以使用 API put-function-recursion-config AWS CLI 命令呼叫:

aws lambda put-function-recursion-config --function-name yourFunctionName --recursive-loop Allow

您可以將函數的組態變更回預設設定,讓 Lambda 在偵測到遞迴循環時終止循環。使用 Lambda 主控台或 編輯函數的組態 AWS CLI。

Console
設定函數以終止遞迴循環 (主控台)
  1. 開啟 Lambda 主控台中的函數頁面

  2. 選擇函數的名稱以開啟函數詳細資訊頁面。

  3. 選擇組態索引標籤,然後選擇並行和遞迴偵測

  4. 除了遞迴迴圈偵測 ,選擇編輯

  5. 選取終止遞迴循環

  6. 選擇 Save (儲存)。

AWS CLI

您可以使用 PutFunctionRecursionConfigAPI來設定函數,讓 Lambda 在偵測到遞迴循環時終止。Terminate 指定遞迴迴圈參數。例如,您可以使用 API put-function-recursion-config AWS CLI 命令呼叫:

aws lambda put-function-recursion-config --function-name yourFunctionName --recursive-loop Terminate

Lambda 遞迴迴圈偵測的支援區域

下列 支援 Lambda 遞迴迴圈偵測 AWS 區域。

  • 美國東部 (維吉尼亞北部)

  • 美國東部 (俄亥俄)

  • 美國西部 (加利佛尼亞北部)

  • 美國西部 (奧勒岡)

  • 非洲 (開普敦)

  • 亞太區域 (香港)

  • 亞太區域 (孟買)

  • 亞太區域 (大阪)

  • 亞太區域 (首爾)

  • 亞太區域 (新加坡)

  • 亞太區域 (雪梨)

  • 亞太區域 (東京)

  • 加拿大 (中部)

  • 歐洲 (法蘭克福)

  • 歐洲 (愛爾蘭)

  • 歐洲 (倫敦)

  • 歐洲 (米蘭)

  • 歐洲 (巴黎)

  • 歐洲 (斯德哥爾摩)

  • Middle East (Bahrain)

  • 南美洲 (聖保羅)