View a markdown version of this page

針對 Lambda 中的執行問題進行疑難排解 - AWS Lambda

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

針對 Lambda 中的執行問題進行疑難排解

當 Lambda 執行時間執行您的函數程式碼時,可能會在已經處理事件一段時間的函數執行個體上處理事件,或是需要初始化新的執行個體。函數初始化期間、您的處理器程式碼處理事件時,或是您的函數傳回回應時 (或是無法傳回時),都可能會發生錯誤。

造成函數執行錯誤的可能原因包含了您程式碼、函數組態、下游資源或是許可的問題。如果您直接叫用您的函數,您會在 Lambda 的回應中看到函數錯誤。如果您透過事件來源映射或是其他服務以非同步方式叫用您的函數,您可能會在日誌、無效字母佇列或是失敗的目的地上找到錯誤。錯誤處理選項和重試行為會因您叫用函數的方式,以及錯誤的類型而有所不同。

當您的函數程式碼或 Lambda 執行時間傳回錯誤時,Lambda 回應中的狀態碼將會是 200 OK。名為 X-Amz-Function-Error 的標頭指示回應中存在錯誤。400 和 500 系列的狀態碼為叫用錯誤預留。

Lambda:使用 Visual Studio Code 進行遠端偵錯

問題:實際 AWS 環境中難以對複雜的 Lambda 函數行為進行故障診斷

Lambda 透過 AWS Toolkit for Visual Studio Code提供遠端偵錯功能。如需設定與一般說明,請參閱使用 Visual Studio Code 遠端偵錯 Lambda 函式。

如需疑難排解、進階使用案例和區域可用性的詳細說明,請參閱 AWS Toolkit for Visual Studio Code 《 使用者指南》中的遠端偵錯 Lambda 函數。

Lambda:執行時間太長

問題:函數執行時間過長。

如果您的程式碼在 Lambda 中執行的時間比在本機機器上更長,它可能會受到函數可用的記憶體或處理能力的限制。設定函數使用額外記憶體以同時增加記憶體和 CPU。

Lambda:非預期的事件承載

問題:函式因格式錯誤的 JSON 或資料驗證不完整而出現錯誤。

所有的 Lambda 函數都會在處理常式的第一個參數中接收事件承載。事件承載是一種 JSON 結構,可能包含陣列和巢狀元素。

當上游服務未使用可靠的流程來檢查其 JSON 結構時,可能會出現 JSON 格式錯誤的問題。當服務串接文字字串或嵌入尚未經過消毒的使用者輸入時,就會發生這種情況。JSON 也經常被序列化,以便在服務之間傳遞。一律做為 JSON 的生產者和消費者剖析 JSON 結構,以確定結構有效。

同樣地,不檢查事件承載中的值範圍可能導致錯誤。此範例顯示計算預扣稅的函數:

exports.handler = async (event) => { let pct = event.taxPct let salary = event.salary // Calculate % of paycheck for taxes return (salary * pct) }

此函數使用事件承載中的薪資和稅率執行計算。但是,程式碼無法檢查屬性是否存在。它也無法檢查資料類型,或確定界限,例如確定稅率在 0 和 1 之間。因此,這些邊界以外的值將產生無意義的結果。類型不正確或缺少屬性會導致執行時期錯誤。

建立測試以確定您的函數能夠處理較大的承載。Lambda 事件承載的大小上限為 1 MB。根據內容,較大的承載可能表示傳遞給函數的項目更多,或內嵌在 JSON 屬性中的二進位資料更多。在這兩種情況下,都可能導致 Lambda 函數的處理量增加。

較大的承載也可能導致逾時。例如,Lambda 函數每 100 毫秒處理一筆記錄,逾時 3 秒。承載中 0-29 個項目的處理成功。但是,一旦承載中的項目數超過 30,函數就會逾時並擲回錯誤。為避免這種情況,請確定設定超時,以處理預期最大項目數的額外處理時間。

Lambda:出乎意料的大型承載大小

問題:函式因大型承載而逾時或導致錯誤。

較大的承載可能導致逾時和錯誤。建議建立測試,確保函式能夠處理預期的最大承載量,並確保函式逾時設定正確。

此外,某些事件承載可能包含指向其他資源的指標。例如,具有 128 MB 記憶體的 Lambda 函數可能會在存放為 S3 物件的 JPG 檔案上執行映像處理。對於較小的映像檔案,函數可如預期執行。

不過,當提供較大的 JPG 檔案做為輸入時,Lambda 函數會因為記憶體耗盡而擲出錯誤。為避免這種情況,測試案例應包含預期資料大小上限的範例。程式碼也應驗證承載大小。

Lambda:JSON 編碼與解碼錯誤

問題:剖析 JSON 輸入時發生 NoSuchKey 例外狀況。

進行檢查,確保正確處理 JSON 屬性。例如,對於 S3 產生的事件,s3.object.key 屬性包含經過 URL 編碼的物件索引鍵名稱。許多函數會將此屬性當成文字來處理,以載入引用的 S3 物件:

範例
const originalText = await s3.getObject({ Bucket: event.Records[0].s3.bucket.name, Key: event.Records[0].s3.object.key }).promise()

此程式碼可與金鑰名稱 james.jpg 搭配使用,但在名稱為 james beswick.jpg 時擲出 NoSuchKey 錯誤。由於 URL 編碼會在金鑰名稱中轉換空格和其他字元,因此必須先確定函數解碼金鑰,再使用此資料:

範例
const originalText = await s3.getObject({ Bucket: event.Records[0].s3.bucket.name, Key: decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")) }).promise()

Lambda:日誌或追蹤沒有出現

問題: 日誌未出現在 CloudWatch Logs 中。

問題:追蹤不會出現在其中 AWS X-Ray。

您的函數需要許可才能呼叫 CloudWatch Logs 和 X-Ray。更新其執行角色以授予許可。新增下列受管政策來啟用日誌和追蹤。

  • AWSLambdaBasicExecutionRole

  • AWSXRayDaemonWriteAccess

將許可新增至您的函數時,亦請對其程式碼或組態進行細微更新。若您函數的執行中執行個體具有已過期的憑證,上述動作會強制停止並取代這些執行個體。

注意

在函數調用之後,日誌可能需要 5 到 10 分鐘才會顯示。

Lambda:並非所有函數的日誌都會顯示

問題:即使我有正確的許可,但 CloudWatch Logs 缺少函數日誌

如果您的 AWS 帳戶 達到其 CloudWatch Logs 配額限制,CloudWatch 會調節函數記錄。發生這種情況時,您的函數輸出的某些日誌可能不會出現在 CloudWatch Logs 中。

如果您的函數輸出日誌的速度過快,Lambda 無法處理它們,這也有可能導致日誌輸出不在 CloudWatch Logs 中顯示。當 Lambda 無法以函數產生日誌的速度將它們傳送到 CloudWatch 時,它會捨棄日誌以防止函數的執行速度變慢。當日誌輸送量單一日誌串流超過 2 MB/s 時,預期會持續觀察到日誌遭捨棄。

如果函數設定為使用 JSON 格式日誌,Lambda 會嘗試在捨棄日誌時將logsDropped 事件傳送至 CloudWatch Logs。不過,當 CloudWatch 對函數的日誌記錄進行限流時,此事件可能無法到達 CloudWatch Logs,因此當 Lambda 捨棄記錄時,您不一定會看到記錄。

若要檢查您的 AWS 帳戶 是否已達到其 CloudWatch Logs 配額限制,請執行下列動作:

  1. 開啟 Service Quotas 主控台。

  2. 在導覽窗格中,選擇 AWS services (AWS 服務)。

  3. 對於 AWS services 清單,搜尋並選取 Amazon CloudWatch Logs。

  4. 在 Service Quotas 清單中,選擇 CreateLogGroup throttle limit in transactions per second、CreateLogStream throttle limit in transactions per second 和 PutLogEvents throttle limit in transactions per second 配額,以檢視您的使用率。

您也可以設定 CloudWatch 警示,以便在帳戶利用率超過您為這些配額指定的限制時提醒您。請參閱建立以靜態閾值為基礎的 CloudWatch 警示,以了解詳細資訊。

如果 CloudWatch Logs 的預設配額限制不足以滿足您的使用案例,您可以請求提高配額。

Lambda:該函數在執行完成之前傳回

問題:(Node.js) 函數在程式碼完成執行前傳回

包括 AWS SDK 在內的許多程式庫會以非同步方式運作。當您進行網路呼叫或是執行需要等待回應的其他操作時,程式庫會傳回稱為 promise 的物件,在背景追蹤操作的進度。

若要等待 promise 解析為回應,請使用 await 關鍵字。這會阻止您的處理器在包含回應的 promise 解析為物件前執行。如果您不需要在程式碼中使用回應中的資料,您可以直接將 promise 傳回執行時間。

有些程式庫不會傳回 promise,但是可以包裝在傳回 promise 的程式碼中。如需詳細資訊,請參閱在 Node.js 中定義 Lambda 函數處理常式。

Lambda:執行非預期的函式版本或別名

問題:未調用的函式版本或別名

當您在主控台或使用 發佈新的 Lambda 函數時 AWS SAM,最新的程式碼版本會以 表示$LATEST。依預設,未指定版本或別名的調用會自動指向函式程式碼的 $LATEST 版本。

如果使用特定的函式版本或別名,這些是除了 $LATEST 之外不可變的已發布函式版本。對這些函式進行疑難排解時,請先確定呼叫者已調用預期的版本或別名。您可以透過檢查函式日誌來完成此操作。所調用的函式版本會始終顯示在 START 日誌行中:

CloudWatch 日誌顯示 START 行,並反白顯示函數版本編號。

Lambda:偵測無限迴圈

問題:因 Lambda 函式而導致無限迴圈模式

Lambda 函數中有兩種無限迴圈類型。第一種在函式本身內部,由一個永不結束的迴圈造成。調用只會在函式逾時之時結束。您可以透過監控逾時來識別這些情況,然後修正迴圈行為。

第二種迴圈類型介於 Lambda 函數和其他 AWS 資源之間。當來自 S3 儲存貯體等資源的事件調用 Lambda 函數,然後該函數與相同來源的資源交互以觸發另一個事件時,就會發生這些情況。這會再次調用函式,進而與同一個 S3 儲存貯體建立另一次互動,依此類推。這些類型的迴圈可能由許多不同的 AWS 事件來源造成,包括 Amazon SQS 佇列和 DynamoDB 資料表。您可以使用遞迴迴圈偵測功能來識別這些模式。

圖表顯示 Lambda 函數與 S3 儲存貯體之間的無限迴圈,其中每個調用都會觸發另一個事件。

透過確保 Lambda 函式寫入與取用端資源不同的資源,即可避免這些迴圈。如果必須將資料發布回取用端資源,請確保新資料不會觸發相同的事件。或者,使用事件篩選功能。例如,以下是針對 S3 和 DynamoDB 資源無限迴圈的兩種建議解決方案:

  • 如果寫回同一個 S3 儲存貯體,請使用與事件觸發程序不同的字首或尾碼。

  • 如果將項目寫入同一個 DynamoDB 資料表,請包含取用端 Lambda 函式可以篩選的屬性。如果 Lambda 找到該屬性,則不會導致另一次調用。

一般:下游服務無法使用

問題:Lambda 函式所依賴的下游服務無法使用

對於呼叫第三方端點或其他下游資源的 Lambda 函式,確保其具備處理服務錯誤與逾時的能力。這些下游資源可能具有可變回應時間,或可能因服務中斷而無法使用。根據實作,如果未在函數程式碼中處理服務的錯誤回應,這些下游錯誤可能會顯示為 Lambda 逾時或例外狀況。

每當函式依賴下游服務時 (例如 API 呼叫),請實作適當的錯誤處理和重試邏輯。對於關鍵服務,Lambda 函式應將指標或日誌發布到 CloudWatch。例如,若第三方付款 API 無法使用,Lambda 函式可以記錄此資訊。然後,您可以設定 CloudWatch 警示來傳送與這些錯誤相關的通知。

由於 Lambda 可以快速擴展,非伺服器下游服務可能難以處理流量激增。有三種常見的應對方法:

  • 快取:如果第三方服務傳回的值不會經常變更,建議快取這些結果。您可以將這些值儲存於函式的全域變數中或其他服務中。例如,來自 Amazon RDS 執行個體的產品清單查詢結果可以在函數內儲存一段時間,以防備援查詢。

  • 佇列:儲存或更新資料時,在 Lambda 函式與資源之間新增 Amazon SQS 佇列。在下游服務處理訊息時,佇列會持久保留資料。

  • 代理:通常使用長效連線 (例如 Amazon RDS 執行個體),使用代理層來匯集和重複使用這些連線。對於關聯式資料庫,Amazon RDS Proxy 是一種服務,旨在協助改善以 Lambda 為基礎的應用程式的可擴展性和彈性。

AWS SDK:版本和更新

問題:執行時間中包含的 AWS SDK 不是最新版本

問題:執行時間中包含的 AWS SDK 會自動更新

解譯語言的執行時間包括 AWS SDK 的版本。Lambda 會定期更新這些執行時期,使用最新的 SDK 版本。若要查詢執行時期內含的 SDK 版本,請參閱下列章節:

若要使用較新版本的 AWS SDK,或將函數鎖定到特定版本,您可以將程式庫與函數程式碼綁定,或建立 Lambda 層。如需建立包含相依性部署套件的詳細資訊,請參閱下列主題:

Node.js

使用 .zip 封存檔部署 Node.js Lambda 函數

Python

使用 .zip 封存檔部署 Python Lambda 函數

Ruby

使用 .zip 封存檔部署 Ruby Lambda 函數

Java

使用 .zip 或 JAR 封存檔部署 Java Lambda 函數

Go

使用 .zip 封存檔部署 Go Lambda 函數

C#

使用 .zip 封存檔建置和部署 C# Lambda 函數

PowerShell

使用 .zip 封存檔部署 PowerShell Lambda 函數

Python:程式庫的載入不正確

問題:(Python) 有些程式庫無法從部署套件正確載入

使用以 C 或 C++ 撰寫延伸模組的程式庫必須在處理器架構與 Lambda 相同的環境中編譯 (Amazon Linux)。如需詳細資訊,請參閱使用 .zip 封存檔部署 Python Lambda 函數。

Java:從 Java 11 更新至 Java 17 後,函數需要更長的時間來處理事件

問題:(Java) 從 Java 11 更新至 Java 17 後,函數需要更長的時間來處理事件

使用 JAVA_TOOL_OPTIONS 參數調校編譯器。Java 17 和更新版本的 Lambda 執行時期變更了預設的編譯器選項。此變更可改善短期函數的冷啟動時間,但先前的行為更適合長時間執行的運算密集函數。將 JAVA_TOOL_OPTIONS 設定為 -XX:-TieredCompilation 以還原至 Java 11 的行為。如需 JAVA_TOOL_OPTIONS 參數的詳細資訊,請參閱 了解 JAVA_TOOL_OPTIONS 環境變數。

Kafka:處理和重試組態問題時發生錯誤

問題:Kafka 事件來源映射無法設定重試設定或失敗時的目的地

Kafka 重試組態和故障時目的地僅適用於啟用佈建模式的事件來源映射。在嘗試設定重試組態ProvisionedPollerConfig之前,請確定您已在 MinimumPollers中設定 。

常見的組態錯誤:

  • 使用 bisect 批次無限次重試 – 當 MaximumRetryAttempts 設定為 -1 (無限) BisectBatchOnFunctionError時,您無法啟用 。設定有限重試限制或停用平分批次。

  • 相同主題遞迴 – Kafka 失敗時目的地主題不能與您的任何來源主題相同。為您的無效字母主題選擇不同的主題名稱。

  • 無效的 Kafka 目的地格式 – 將 Kafka 主題指定為失敗時的目的地時,請使用 kafka://<topic-name> 格式。

  • kafka:WriteData 許可問題 – 確保您的執行角色具有目的地主題的kafka-cluster:WriteData許可。主題不存在逾時例外狀況,或寫入 API 限流問題可能需要提高帳戶限制。