

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

# 針對 Lambda 中的執行問題進行疑難排解
<a name="troubleshooting-execution"></a>

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

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

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

**Topics**
+ [Lambda：使用 Visual Studio Code 進行遠端偵錯](#troubleshooting-execution-remote-debugging)
+ [Lambda：執行時間太長](#troubleshooting-execution-toolong)
+ [Lambda：非預期的事件承載](#troubleshooting-execution-unexpected-payload)
+ [Lambda：出乎意料的大型承載大小](#troubleshooting-execution-large-payload)
+ [Lambda：JSON 編碼與解碼錯誤](#troubleshooting-execution-json-encoding)
+ [Lambda：日誌或追蹤沒有出現](#troubleshooting-execution-logstraces)
+ [Lambda：並非所有函數的日誌都會顯示](#troubleshooting-execution-missinglogs)
+ [Lambda：該函數在執行完成之前傳回](#troubleshooting-execution-unfinished)
+ [Lambda：執行非預期的函式版本或別名](#unintended-function)
+ [Lambda：偵測無限迴圈](#infinite-loops)
+ [一般：下游服務無法使用](#downstream-unavailability)
+ [AWS SDK：版本和更新](#troubleshooting-execution-versions)
+ [Python：程式庫的載入不正確](#troubleshooting-execution-libraries)
+ [Java：從 Java 11 更新至 Java 17 後，函數需要更長的時間來處理事件](#troubleshooting-execution-java-perf)
+ [Kafka：處理和重試組態問題時發生錯誤](#troubleshooting-kafka-error-handling)

## Lambda：使用 Visual Studio Code 進行遠端偵錯
<a name="troubleshooting-execution-remote-debugging"></a>

**問題：***在實際 AWS 環境中難以疑難排解複雜的 Lambda 函數行為*

Lambda 透過 AWS Toolkit for Visual Studio Code提供遠端偵錯功能。如需設定與一般說明，請參閱[使用 Visual Studio Code 遠端偵錯 Lambda 函式](debugging.md)。

如需疑難排解、進階使用案例和區域可用性的詳細說明，請參閱 AWS Toolkit for Visual Studio Code 《 使用者指南》中的[遠端偵錯 Lambda 函數](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/lambda-remote-debug.html)。

## Lambda：執行時間太長
<a name="troubleshooting-execution-toolong"></a>

**問題：***函數執行時間過長。*

如果您的程式碼在 Lambda 中執行的時間比在本機機器上長，可能是因為函數可用的記憶體或處理能力受到限制。[設定函數使用額外記憶體](configuration-memory.md)以同時增加記憶體和 CPU。

## Lambda：非預期的事件承載
<a name="troubleshooting-execution-unexpected-payload"></a>

**問題：***函式因格式錯誤的 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：出乎意料的大型承載大小
<a name="troubleshooting-execution-large-payload"></a>

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

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

此外，某些事件承載可能包含指向其他資源的指標。例如，具有 128 MB 記憶體的 Lambda 函式，可以對以物件形式儲存於 S3 的 JPG 檔案進行映像處理。對於較小的映像檔案，函數可如預期執行。不過，當提供較大的 JPG 檔案做為輸入時，Lambda 函數會因為記憶體耗盡而擲出錯誤。為避免這種情況，測試案例應包含預期資料大小上限的範例。程式碼也應驗證承載大小。

## Lambda：JSON 編碼與解碼錯誤
<a name="troubleshooting-execution-json-encoding"></a>

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

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

**Example**  

```
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 編碼會在金鑰名稱中轉換空格和其他字元，因此必須先確定函數解碼金鑰，再使用此資料：

**Example**  

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

## Lambda：日誌或追蹤沒有出現
<a name="troubleshooting-execution-logstraces"></a>

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

**問題：***追蹤不會出現在 中 AWS X-Ray。*

您的函數需要許可才能呼叫 CloudWatch Logs 和 X-Ray。更新其[執行角色](lambda-intro-execution-role.md)以授予許可。新增下列受管政策來啟用日誌和追蹤。
+ **AWSLambdaBasicExecutionRole**
+ **AWSXRayDaemonWriteAccess**

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

**注意**  
在函數調用後，日誌可能需要 5 到 10 分鐘才會顯示。

## Lambda：並非所有函數的日誌都會顯示
<a name="troubleshooting-execution-missinglogs"></a>

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

如果您的 AWS 帳戶 達到其 [CloudWatch Logs 配額限制](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/cloudwatch_limits_cwl.html)，CloudWatch 會調節函數記錄。發生這種情況時，您的函數的一些日誌輸出可能不會在 CloudWatch Logs 中顯示。

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

如果函數設定為使用 [JSON 格式日誌](monitoring-cloudwatchlogs-logformat.md)，Lambda 會嘗試在捨棄日誌時將[`logsDropped`](telemetry-schema-reference.md#platform-logsDropped) 事件傳送至 CloudWatch Logs。不過，當 CloudWatch 對函數的日誌記錄進行限流時，此事件可能無法到達 CloudWatch Logs，因此當 Lambda 捨棄記錄時，您不一定會看到記錄。

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

1. 開啟 [Service Quotas 主控台](https://console.aws.amazon.com/servicequotas)。

1. 在導覽窗格中，選擇 **AWS services (AWS 服務)**。

1. 對於 **AWS services** 清單，搜尋並選取 Amazon CloudWatch Logs。

1. 在 **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 警示](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ConsoleAlarms.html)，以了解詳細資訊。

如果 CloudWatch Logs 的預設配額限制不足以滿足您的使用案例，您可以[請求提高配額](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)。

## Lambda：該函數在執行完成之前傳回
<a name="troubleshooting-execution-unfinished"></a>

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

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

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

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

## Lambda：執行非預期的函式版本或別名
<a name="unintended-function"></a>

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

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

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

![\[除錯操作圖 1\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/debugging-ops-figure-1.png)


## Lambda：偵測無限迴圈
<a name="infinite-loops"></a>

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

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

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

![\[除錯操作圖 2\]](http://docs.aws.amazon.com/zh_tw/lambda/latest/dg/images/debugging-ops-figure-2.png)


透過確保 Lambda 函式寫入與取用端資源不同的資源，即可避免這些迴圈。如果必須將資料發布回取用端資源，請確保新資料不會觸發相同的事件。或者，使用[事件篩選](invocation-eventfiltering.md)功能。例如，以下是針對 S3 和 DynamoDB 資源無限迴圈的兩種建議解決方案：
+ 如果寫回同一個 S3 儲存貯體，請使用與事件觸發程序不同的字首或尾碼。
+ 如果將項目寫入同一個 DynamoDB 資料表，請包含取用端 Lambda 函式可以篩選的屬性。如果 Lambda 找到該屬性，則不會導致另一次調用。

## 一般：下游服務無法使用
<a name="downstream-unavailability"></a>

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

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

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

由於 Lambda 可以快速擴展，非無伺服器下游服務可能難以應對流量激增的狀況。有三種常見的應對方法：
+  **快取**：如果第三方服務傳回的值不會經常變更，建議快取這些結果。您可以將這些值儲存於函式的全域變數中或其他服務中。例如，來自 Amazon RDS 執行個體的產品清單查詢結果可以在函數內儲存一段時間，以防備援查詢。
+  **佇列**：儲存或更新資料時，在 Lambda 函式與資源之間新增 Amazon SQS 佇列。在下游服務處理訊息時，佇列會持久保留資料。
+  **代理**：通常使用長效連線 (例如 Amazon RDS 執行個體)，使用代理層來匯集和重複使用這些連線。對於關聯式資料庫，[Amazon RDS Proxy](https://github.com/aws-samples/s3-to-lambda-patterns/tree/master/docrepository) 是一種服務，旨在協助改善以 Lambda 為基礎的應用程式的可擴展性和彈性。

## AWS SDK：版本和更新
<a name="troubleshooting-execution-versions"></a>

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

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

解譯語言的執行時間包括 AWS SDK 的版本。Lambda 會定期更新這些執行時期，使用最新的 SDK 版本。若要查詢執行時期內含的 SDK 版本，請參閱下列章節：
+ [執行時期內含 SDK 版本 (Node.js)](lambda-nodejs.md#nodejs-sdk-included)
+ [執行時期內含 SDK 版本 (Python)](lambda-python.md#python-sdk-included)
+ [執行時期內含 SDK 版本 (Ruby)](lambda-ruby.md#ruby-sdk-included)

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

------
#### [ Node.js ]

[使用 .zip 封存檔部署 Node.js Lambda 函數](nodejs-package.md) 

------
#### [ Python ]

 [使用 .zip 封存檔部署 Python Lambda 函數](python-package.md) 

------
#### [ Ruby ]

 [使用 .zip 封存檔部署 Ruby Lambda 函數](ruby-package.md) 

------
#### [ Java ]

 [使用 .zip 或 JAR 封存檔部署 Java Lambda 函數](java-package.md) 

------
#### [ Go ]

 [使用 .zip 封存檔部署 Go Lambda 函數](golang-package.md) 

------
#### [ C\$1 ]

 [使用 .zip 封存檔建置和部署 C＃ Lambda 函數](csharp-package.md) 

------
#### [ PowerShell ]

 [使用 .zip 封存檔部署 PowerShell Lambda 函數](powershell-package.md) 

------

## Python：程式庫的載入不正確
<a name="troubleshooting-execution-libraries"></a>

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

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

## Java：從 Java 11 更新至 Java 17 後，函數需要更長的時間來處理事件
<a name="troubleshooting-execution-java-perf"></a>

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

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

## Kafka：處理和重試組態問題時發生錯誤
<a name="troubleshooting-kafka-error-handling"></a>

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

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

常見的組態錯誤：
+ **使用 bisect 批次無限次重試** – 當 `MaximumRetryAttempts` 設定為 -1 （無限） `BisectBatchOnFunctionError`時，您無法啟用 。設定有限重試限制或停用平分批次。
+ **相同主題遞迴** – Kafka 失敗時目的地主題不能與您的任何來源主題相同。為您的無效字母主題選擇不同的主題名稱。
+ **無效的 Kafka 目的地格式** – 將 Kafka 主題指定為失敗時的目的地時，請使用 `kafka://<topic-name>` 格式。
+ **kafka：WriteData 許可問題** – 確保您的執行角色具有目的地主題的`kafka-cluster:WriteData`許可。主題不存在逾時例外狀況，或寫入 API 限流問題可能需要提高帳戶限制。