了解 Lambda 執行環境生命週期 - AWS Lambda

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

了解 Lambda 執行環境生命週期

Lambda 會在執行環境中調用您的函數,該環境可提供安全且隔離的執行時間環境。執行環境會管理執行函式所需的資源。執行環境也會提供函式執行階段的生命週期支援,以及與函式相關聯的任何外部延伸項目

函數的執行時間會使用 Runtime API 與 Lambda 進行通訊。延伸項目會使用 Extensions API 與 Lambda 進行通訊。延伸項目還可以透過使用遙測 API 來接收函數的日誌訊息和其他遙測項目。

執行環境的架構圖表。

當您建立 Lambda 函數時,您將指定組態資訊,例如您的函數允許的記憶體數量與執行時間上限。Lambda 會使用此資訊來設定執行環境。

函式的執行階段和每個外部延伸項目都是在執行環境中執行的程序。許可、資源、認證和環境變數會在函式和延伸項目之間共用。

Lambda 執行環境生命週期

Lambda 生命週期階段:初始化、調用、關閉

每個階段都以 Lambda 傳送到執行階段和所有已註冊延伸項目的事件開始。執行時間和每個已註冊延伸項目都會透過傳送 Next API 請求來表示已完成。當執行時間和每個延伸項目已完成且沒有擱置的事件時,Lambda 凍結執行環境。

初始化階段

Init 階段中,Lambda 會執行三項任務:

  • 啟動所有延伸項目 (Extension init)

  • Bootstrap 執行時間 (Runtime init)

  • 執行該函式的靜態代碼 (Function init)

  • 執行任何檢查點前的執行時期勾點 (僅限 Lambda SnapStart)

當執行階段和所有延伸項目透過傳送 Next API 請求發出訊號表示它們已準備就緒時,Init 階段便會結束。Init 階段限制為 10 秒。如果所有三項任務都未在 10 秒內完成,Lambda 會在第一次函數調用時以設定的函數逾時重試 Init 階段。

Lambda SnapStart 啟動的情況下,發佈函數版本時會發生 Init 階段。Lambda 會儲存初始化執行環境的記憶體和磁碟狀態快照、保留加密的快照,並快取以進行低延遲存取。如果您擁有檢查點前的執行時期勾點,則程式碼會在 Init 階段結束時執行。

注意

10 秒逾時不適用於使用佈建並行或 SnapStart 的函數。對於佈建並行和 SnapStart 函數,初始化程式碼最多可以執行 15 分鐘。時間限制為 130 秒或設定的函數逾時 (最長 900 秒),以較長者為準。

使用佈建並行時,當您設定函數的電腦設定,Lambda 會初始化執行環境。Lambda 也可確保初始化的執行環境在調用之前隨時可用。您會發現函數調用和初始化階段之間出現差距。根據函數的執行期和記憶體組態,您也會在初始化的執行環境上第一次調用時看到變數延遲。

對於使用隨需並行的函數,Lambda 偶爾會在調用請求之前初始化執行環境。發生這種情況時,您也會注意到函數初始化和調用階段之間出現時間差。建議您不要依賴此行為。

初始化階段期間出現的失敗

如果在 Init 階段期間函數當機或出現逾時,Lambda 會在 INIT_REPORT 日誌檔中發出錯誤資訊。

範例 — 逾時的 INIT_REPORT 日誌
INIT_REPORT Init Duration: 1236.04 ms Phase: init Status: timeout
範例 — 延伸失敗的 INIT_REPORT 日誌
INIT_REPORT Init Duration: 1236.04 ms Phase: init Status: error Error Type: Extension.Crash

如果 Init 階段成功,除非已啟用 SnapStart佈建並行,否則 Lambda 不會發出 INIT_REPORT 日誌。SnapStart 和佈建並行函數一律會發出 INIT_REPORT。如需詳細資訊,請參閱監控 Lambda SnapStart

還原階段 (僅限 Lambda SnapStart)

第一次調用 SnapStart 函數且函數擴展時,Lambda 會從保留的快照繼續新的執行環境,而不是從頭開始初始化函數。如果您有還原後執行期掛鉤,程式碼會在Restore階段結束時執行。您需要支付還原後執行期掛鉤的期間費用。執行時間必須載入,且還原後執行時間勾點必須在逾時限制 (10 秒) 內完成。否則,您將收到 SnapStartTimeoutException 訊息。Restore 階段完成時,Lambda 會調用函數處理常式 (調用階段)。

還原階段期間出現的失敗

如果 Restore 階段失敗,Lambda 會在 RESTORE_REPORT 日誌檔中發出錯誤資訊。

範例 — 逾時的 RESTORE_REPORT 日誌
RESTORE_REPORT Restore Duration: 1236.04 ms Status: timeout
範例 — 執行期勾點失敗的 RESTORE_REPORT 日誌
RESTORE_REPORT Restore Duration: 1236.04 ms Status: error Error Type: Runtime.ExitError

如需RESTORE_REPORT 日誌的詳細資訊,請參閱 監控 Lambda SnapStart

調用階段

調用 Lambda 函數以回應 Next API 請求時,Lambda 會將 Invoke 事件傳送至執行時間和每個延伸項目。

該函式的逾時設定會限制整個 Invoke 階段的持續時間。例如,如果您將函式逾時設定為 360 秒,則函式和所有延伸項目都需要在 360 秒內完成。請注意,沒有獨立的調用後階段。持續時間是所有調用時間 (執行階段 + 延伸項目) 的總和,直到函式和所有延伸項目完成執行後才會計算。

調用階段會在執行階段後結束,所有延伸項目訊號都透過傳送 Next API 請求完成。

調用階段期間出現的故障

如果 Lambda 函數當機或在 Invoke 階段逾時,Lambda 會重設執行環境。下圖會說明發生調用故障時 Lambda 執行環境的行為:

執行環境範例:初始化、調用、調用出現錯誤、調用、關閉

在前一張示意圖中:

  • 第一階段是 INIT 階段,執行期間未發生錯誤。

  • 第二階段是 INVOKE 階段,執行期間未發生錯誤。

  • 假設您的函數在某個時間點發生調用故障 (例如函數逾時或執行階段錯誤)。第三階段 (標記為「INVOKE WITH ERROR」) 會說明此狀況。發生此狀況時,Lambda 服務會進行重設。重設的行為會與 Shutdown 事件一樣。首先,Lambda 會關閉執行階段,然後將 Shutdown 事件傳送給每個已註冊的外部延伸項目。事件會包括關閉的原因。如果將此環境用於新的調用,Lambda 便會在下一次調用時重新初始化延伸項目和執行階段。

    請注意,在下一個初始化階段之前,Lambda 重設不會清除 /tmp 目錄內容。這種行為與一般關機階段一致。

    注意

    AWS 目前正在對 Lambda 服務實作變更。由於這些變更,您可能會看到系統日誌訊息的結構和內容,與 AWS 帳戶中不同 Lambda 函數發出的追蹤區段之間存在細微差異。

    如果函數的系統日誌組態設為純文字,則此變更會影響函數發生調用失敗時在 CloudWatch Logs 中擷取的日誌訊息。下列範例展示了舊格式和新格式的日誌輸出。

    這些變化將在未來幾週內實作,除中國和 GovCloud 區域以外,所有 AWS 區域 中的所有函數都會轉換至使用新格式的日誌訊息和追蹤區段。

    範例 CloudWatch Logs 日誌輸出 (執行時期或延伸項目損毀) - 舊式
    START RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Version: $LATEST RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Error: Runtime exited without providing a reason Runtime.ExitError END RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 REPORT RequestId: c3252230-c73d-49f6-8844-968c01d1e2e1 Duration: 933.59 ms Billed Duration: 934 ms Memory Size: 128 MB Max Memory Used: 9 MB
    範例 CloudWatch Logs 日誌輸出 (函數逾時) - 舊式
    START RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Version: $LATEST 2024-03-04T17:22:38.033Z b70435cc-261c-4438-b9b6-efe4c8f04b21 Task timed out after 3.00 seconds END RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 REPORT RequestId: b70435cc-261c-4438-b9b6-efe4c8f04b21 Duration: 3004.92 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 33 MB Init Duration: 111.23 ms

    CloudWatch Logs 的新格式包括 REPORT 行中的額外 status 欄位。在執行時期或延伸項目損毀的情況下,該 REPORT 行也包含欄位 ErrorType

    範例 CloudWatch Logs 日誌輸出 (執行時期或延伸項目損毀) - 新式
    START RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd Version: $LATEST END RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd REPORT RequestId: 5b866fb1-7154-4af6-8078-6ef6ca4c2ddd Duration: 133.61 ms Billed Duration: 133 ms Memory Size: 128 MB Max Memory Used: 31 MB Init Duration: 80.00 ms Status: error Error Type: Runtime.ExitError
    範例 CloudWatch Logs 日誌輸出 (函數逾時) - 新式
    START RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda Version: $LATEST END RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda REPORT RequestId: 527cb862-4f5e-49a9-9ae4-a7edc90f0fda Duration: 3016.78 ms Billed Duration: 3016 ms Memory Size: 128 MB Max Memory Used: 31 MB Init Duration: 84.00 ms Status: timeout
  • 第四階段指的是出現調用故障後立即進入的 INVOKE 階段。在此階段中,Lambda 會透過重新執行 INIT 階段來再次初始化環境。(我們將其稱為 隱藏的初始化。) 發生隱藏的初始化時,Lambda 不會在 CloudWatch Logs 中明確回報其他 INIT 階段。相反地,您可能會注意到 REPORT 行中的持續時間包含其他的 INIT 持續時間以及 INVOKE 持續時間。舉例來說,假設您在 CloudWatch 中看到以下日誌:

    2022-12-20T01:00:00.000-08:00 START RequestId: XXX Version: $LATEST 2022-12-20T01:00:02.500-08:00 END RequestId: XXX 2022-12-20T01:00:02.500-08:00 REPORT RequestId: XXX Duration: 3022.91 ms Billed Duration: 3000 ms Memory Size: 512 MB Max Memory Used: 157 MB

    在這個例子中,REPORT 和 START 時間戳記之間的差距是 2.5 秒。這與回報的 3022.91 毫秒持續時間不相符,因為它不會將 Lambda 執行的額外 INIT(隱藏的初始化) 納入考量。在這個例子中,您可以推斷實際的 INVOKE 階段花費了 2.5 秒的時間。

    若要深入了解此行為,您可以使用 使用遙測 API 即時存取延伸功能的遙測資料. 調用階段發生隱藏的初始化時,遙測 API 便會透過 phase=invoke 發送 INIT_STARTINIT_RUNTIME_DONEINIT_REPORT 事件。

  • 第五階段指的是 SHUTDOWN 階段,執行期間未發生錯誤。

關閉階段

當 Lambda 即將關閉執行時間,它會將 Shutdown 事件傳送至每個已註冊外部延伸。延伸項目可以使用此時間進行最終清理工作。Shutdown 事件是對 Next API 請求的回應。

持續時間:整個 Shutdown 階段上限為 2 秒。如果執行時間或任何延伸項目沒有回應,Lambda 會透過訊號 (SIGKILL) 加以終止。

在函數和所有延伸項目完成之後,Lambda 會維護執行環境一段時間,並預期另一個函數調用。不過,Lambda 每隔幾小時終止一次執行環境,以允許執行時期更新和維護,即使對於持續調用的函數也是如此。您不應該假設執行環境將無限期持續運作。如需詳細資訊,請參閱在函數中實作無狀態

再次調用該函數時,Lambda 會解凍環境以供重複使用。重複使用執行環境具有下列含義:

  • 在函數處理常式方法外宣告的物件會保持初始化,於再次呼叫函數時提供額外的最佳化。例如,假設您的 Lambda 函數建立資料庫連線,而不是重建連線,那麼在後續呼叫時便會使用原始連線。建議您在程式碼中新增邏輯,在建立連線前先確認是否存在既有連線。

  • 每個執行環境都會在 /tmp 目錄中提供 512 MB 到 10,240 MB 的磁碟空間,增量為 1 MB。執行內容凍結時,目錄環境會凍結,所提供的暫時性可用於多重調用。您可以新增額外的程式碼,確認快取是否具有您已儲存的資料。如需部署大小限制的詳細資訊,請參閱Lambda 配額

  • 如果 Lambda 重複使用執行環境,則會恢復由 Lambda 函數啟動且在函數結束時沒有完成的背景程序或回呼。請確定程式碼中的任何背景程序或回呼在程式碼存在前已完成。

冷啟動和延遲

當 Lambda 收到透過 Lambda API 執行函數的請求時,服務會先準備執行環境。在此初始化階段,服務會下載您的程式碼、啟動環境,並在主處理常式之外執行任何初始化程式碼。最後,Lambda 會執行處理常式程式碼。

效能最佳化圖 1

在此圖表中,下載程式碼和設定環境的前兩個步驟通常稱為「冷啟動」。您這次不需要支付費用,但它會為整體調用持續時間增加延遲。

調用完成後,執行環境會凍結。為了改善資源管理和效能,Lambda 會保留執行環境一段時間。在此期間,如果另一個請求到達相同函數,Lambda 可以重複使用環境。第二個請求通常會更快完成,因為執行環境已完全設定。這就是所謂的「暖啟動」。

冷啟動通常發生在不到 1% 的調用中。冷啟動的持續時間從低於 100 毫秒至超過 1 秒不等。一般而言,冷啟動在開發和測試函數中通常比生產工作負載更常見。這是因為開發和測試函數的調用頻率通常較低。

使用佈建並行減少冷啟動

如果您需要工作負載的可預測函數開始時間,建議採用佈建並行解決方案,以確保盡可能降低延遲。此功能會預先初始化執行環境,減少冷啟動。

例如,佈建並行為 6 的函數有 6 個預先暖機的執行環境。

效能最佳化圖 4

最佳化靜態初始化

靜態初始化在處理常式程式碼開始在函數中執行之前進行。這是您提供的初始化程式碼,位於主處理常式之外。此程式碼通常用於匯入程式庫和相依性、設定組態,以及初始化對其他服務的連線。

下列 Python 範例顯示在叫用期間執行lambda_handler函數之前,在初始化階段匯入和設定模組,以及建立 Amazon S3 用戶端。

import os import json import cv2 import logging import boto3 s3 = boto3.client('s3') logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): # Handler logic...

函數執行前延遲的最大貢獻者來自初始化程式碼。此程式碼會在第一次建立新的執行環境時執行。如果調用使用暖執行環境,則不會再次執行初始化程式碼。影響初始化程式碼延遲的因素包括:

  • 函數套件的大小,包括匯入的程式庫和相依項以及 Lambda 層。

  • 程式碼和初始化工作的數量。

  • 程式庫和其他服務在設定連線及其他資源方面的表現。

開發人員可以採取許多步驟來最佳化靜態初始化延遲。如果一個函數具有許多物件和連線,您可以將單一函數重新架構為多個專用函數。這些個別較小,且每個的初始化程式碼較少。

重要的是,函數僅匯入所需的程式庫和相依項。例如,如果您只在 AWS SDK 中使用 Amazon DynamoDB,您可以要求個別服務,而不是整個 SDK。比較下列三個範例:

// Instead of const AWS = require('aws-sdk'), use:
const DynamoDB = require('aws-sdk/clients/dynamodb')

// Instead of const AWSXRay = require('aws-xray-sdk'), use:
const AWSXRay = require('aws-xray-sdk-core')

// Instead of const AWS = AWSXRay.captureAWS(require('aws-sdk')), use:
const dynamodb = new DynamoDB.DocumentClient()
AWSXRay.captureAWSClient(dynamodb.service)

靜態初始化通常是開啟資料庫連線的最佳位置,讓函數透過多次呼叫重複使用對相同執行環境的連線。但是,您可能具有大量僅在函數的某些執行路徑中使用的物件。在這種情況下,您可以在全域範圍內延遲載入變數,以縮短靜態初始化持續時間。

避免全域變數以取得內容特定資訊。如果您的函數具有僅在單次調用的生命週期內使用並在下次調用時重設的全域變數,請使用處理常式本機的變數範圍。這不僅可以防止調用間的全域變數洩漏,還可以改善靜態初始化效能。