

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

# 使用 Lambda SnapStart 改善啟動效能
<a name="snapstart"></a>

Lambda SnapStart 可提供低至一秒的啟動效能，通常不會變更函數程式碼。SnapStart 可讓您更輕鬆地建置高回應和可擴展應用程式，而無需佈建資源或實作複雜的效能最佳化。

啟動延遲的最大歸因 (通常稱為冷啟動時間) 是 Lambda 花費在初始化函數的時間，其中包括載入函數的程式碼、啟動執行階段以及初始化函數程式碼。使用 SnapStart，Lambda 會在您發佈函數版本時初始化您的函數。Lambda 會擷取已初始化[執行環境](lambda-runtime-environment.md)的記憶體和磁碟狀態的 [Firecracker microVM](https://aws.amazon.com/blogs/opensource/firecracker-open-source-secure-fast-microvm-serverless/) 快照、將快照加密，並智慧地進行快取以最佳化擷取延遲。

為了確保彈性，Lambda 會維護每個快照的多個副本。Lambda 會使用最新的執行時期和安全更新來自動修補快照及其副本。第一次調用函數版本時且呼叫縱向擴展時，Lambda 會從快取的快照恢復新的執行環境，而不是從頭開始執行，進而改善啟動延遲。

**重要**  
如果您的應用程式依賴狀態的唯一性，則必須評估函數程式碼，並確認其對快照作業具有復原能力。如需詳細資訊，請參閱[使用 Lambda SnapStart 處理唯一性](snapstart-uniqueness.md)。

**Topics**
+ [

## 何時使用 SnapStart
](#snapstart-use-cases)
+ [

## 支援的功能和限制
](#snapstart-runtimes)
+ [

## 支援的區域
](#snapstart-supported-regions)
+ [

## 相容性考量
](#snapstart-compatibility)
+ [

## SnapStart 定價
](#snapstart-pricing)
+ [

# 啟動及管理 Lambda SnapStart
](snapstart-activate.md)
+ [

# 使用 Lambda SnapStart 處理唯一性
](snapstart-uniqueness.md)
+ [

# 在 Lambda 函數快照之前或之後實作程式碼
](snapstart-runtime-hooks.md)
+ [

# 監控 Lambda SnapStart
](snapstart-monitoring.md)
+ [

# Lambda SnapStart 的安全模型
](snapstart-security.md)
+ [

# 最大化 Lambda SnapStart 效能
](snapstart-best-practices.md)
+ [

# 對 Lambda 函數的 SnapStart 錯誤進行故障診斷
](snapstart-troubleshooting.md)

## 何時使用 SnapStart
<a name="snapstart-use-cases"></a>

Lambda SnapStart 旨在解決一次性初始化程式碼帶來的延遲差異，例如載入模組相依項或架構。這些操作有時可能需要幾秒鐘才能在初始調用期間完成。在最佳情況下，使用 SnapStart 將此延遲從數秒減少到低至次秒。SnapStart 搭配大規模函數調用使用時效果最佳。不常調用的函數效能改進效果可能不會相同。

SnapStart 特別適用於兩種主要應用程式類型：
+ **延遲敏感 API 和使用者流程：**屬於關鍵 API 端點或面向使用者的流程的函數可受益於 SnapStart 降低的延遲和改善的回應時間。
+ **延遲敏感資料處理工作流程：**使用 Lambda 函數的限時資料處理工作流程可以透過減少異常函數初始化延遲來實現更佳的輸送量。

[佈建並行](provisioned-concurrency.md)可讓函數保持初始化，並準備好在兩位數的毫秒內回應。如果應用程式有嚴格的冷啟動延遲要求，且 SnapStart 無法充分解決，請使用佈建並行。

## 支援的功能和限制
<a name="snapstart-runtimes"></a>

SnapStart 適用於下列 [Lambda 受管執行時期](lambda-runtimes.md)：
+ Java 11 及更高版本
+ Python 3.12 及更高版本
+ .NET 8 及更高版本。如果使用的是[適用於 .NET 的 Lambda Annotations 架構](csharp-handler.md#csharp-handler-annotations)，請升級至 [Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) 1.6.0 版或更新版本，以確保與 SnapStart 的相容性。

不支援其他受管執行期 (例如 `nodejs24.x` 和 `ruby3.4`)、[僅限作業系統的執行期](runtimes-provided.md) 和[容器映像](images-create.md)。

SnapStart 不支援[佈建並行](provisioned-concurrency.md)、[Amazon Elastic File System (Amazon EFS)](https://docs.aws.amazon.com/efs/latest/ug/accessing-fs.html) 或大於 512 MB 的暫時性儲存。

**注意**  
您只能對指向版本的[已發佈函數版本](configuration-versions.md#configuration-versions-config)和[別名](configuration-aliases.md)使用 SnapStart。不能對函數的未發佈版本 (\$1LATEST) 使用 SnapStart。

## 支援的區域
<a name="snapstart-supported-regions"></a>

Lambda SnapStart 已在所有[商業區域](https://docs.aws.amazon.com/general/latest/gr/glos-chap.html#region)中推出，但亞太區域 (紐西蘭) 與亞太區域 (台北) 除外。

## 相容性考量
<a name="snapstart-compatibility"></a>

透過 SnapStart，Lambda 會使用單一快照做為多個執行環境的初始狀態。如果您的函數在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)使用以下任何一項，那麼您可能需要在使用 SnapStart 之前進行一些變更：

**唯一性**  
如果您的初始化程式碼會產生包含在快照中的唯一內容，則在跨執行環境中重複使用該內容時，該內容可能不是唯一的。若要在使用 SnapStart 時保持唯一性，您必須在初始化後產生唯一的內容。這包括唯一 ID、唯一密碼，以及用來產生偽隨機性的熵。若要了解如何還原唯一性，請參閱：[使用 Lambda SnapStart 處理唯一性](snapstart-uniqueness.md)。

**網路連線**  
Lambda 從快照恢復函數時，無法保證函數在初始化階段建立的連線狀態。驗證網路連線的狀態，並視需要重新建立。在大多數情況下， AWS 軟體開發套件建立的網路連線會自動恢復。針對其他連線，請檢閱[最佳實務](snapstart-best-practices.md)。

**暫存資料**  
某些函數會在初始化階段下載或初始化暫存資料，例如臨時憑證或快取的時間戳記。請先重新整理函數處理常式中的暫時性資料再使用處理常式，即使沒有使用 SnapStart 也是如此。

## SnapStart 定價
<a name="snapstart-pricing"></a>

**注意**  
對於 Java 受管執行時期，SnapStart 無需額外費用。我們會根據函數的請求數量、程式碼執行的時間，以及為函數配置的記憶體向您收費。

使用 SnapStart 的成本包括下列項目：
+ **快取：**對於在啟用 SnapStart 的情況下發布的每個函數版本，需要支付快取和維護快照的成本。價格取決於您配置給函數的[記憶體](configuration-memory.md)容量。需要支付最少 3 小時的費用。只要您的函式處於[作用中](snapstart-activate.md#snapstart-active)狀態，就會持續產生費用。使用 [ListVersionsByFunction](https://docs.aws.amazon.com/lambda/latest/api/API_ListVersionsByFunction.html) API 動作來識別函式版本，然後使用 [DeleteFunction](https://docs.aws.amazon.com/lambda/latest/api/API_DeleteFunction.html) 刪除未使用的版本。若要自動刪除未使用的函數版本，請參閱 Serverless Land 上的 [Lambda 版本清除](https://serverlessland.com/workflows/step-functions-lambda-version-cleanup)模式。
+ **還原：**每次從快照中還原函數執行個體時，都會支付還原費用。價格取決於您配置給函數的記憶體容量。

如同所有 Lambda 函數一樣，持續時間費用適用於函數處理常式中執行的程式碼。對於 SnapStart 函數，持續時間費用也適用於在處理常式之外宣告的初始化程式碼、執行時期進行載入所花的時間以及在[執行時期勾點](snapstart-runtime-hooks.md)中執行的任何程式碼。持續時間是從程式碼開始執行的時間開始計算，直到傳回資料或結束為止，四捨五入至最接近的 1 ms。Lambda 會維護快照的快取副本以實現彈性，並自動套用軟體更新，例如執行時期升級和安全修補程式。每次 Lambda 重新執行初始化程式碼以套用軟體更新時，都會收取費用。

如需有關使用 SnapStart 的成本詳細資訊，請參閱 [AWS Lambda 定價](https://aws.amazon.com/lambda/pricing/#SnapStart_Pricing)。

# 啟動及管理 Lambda SnapStart
<a name="snapstart-activate"></a>

若要使用 SnapStart，請對新的或現有的 Lambda 函數啟動 SnapStart。然後發布並調用函數版本。

**Topics**
+ [

## 啟動 SnapStart (主控台)
](#snapshot-console)
+ [

## 啟動 SnapStart (AWS CLI)
](#snapshot-cli)
+ [

## 啟動 SnapStart (API)
](#snapshot-api)
+ [

## Lambda SnapStart 和函數狀態
](#snapstart-function-states)
+ [

## 更新快照
](#update-snapshot)
+ [

## 使用 SnapStart AWS SDKs
](#snapstart-credentials)
+ [

## 搭配 CloudFormation AWS SAM、 和 使用 SnapStart AWS CDK
](#snapstart-cfn-sam)
+ [

## 刪除快照
](#snapshot-delete)

## 啟動 SnapStart (主控台)
<a name="snapshot-console"></a>

**為函數啟動 SnapStart**

1. 開啟 Lambda 主控台中的 [函數頁面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 選擇函數的名稱。

1. 選擇**組態**，然後選擇**一般組態**。

1. 在**一般組態**窗格中，選擇**編輯**。

1. 在**編輯基本設定**頁面中，為 **SnapStart** 選擇**已發布的版本**。

1. 選擇 **儲存** 。

1. [發佈函數版本](configuration-versions.md#configuration-versions-config)。Lambda 會初始化程式碼、建立初始化執行環境的快照，然後快取快照以實現低延遲存取。

1. [調用函數版本](configuration-versions.md#versioning-versions-using)。

## 啟動 SnapStart (AWS CLI)
<a name="snapshot-cli"></a>

**為現有函數啟動 SnapStart**

1. 執行 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) 命令搭配 **--snap-start** 選項來更新函數組態。

   ```
   aws lambda update-function-configuration \
     --function-name my-function \
     --snap-start ApplyOn=PublishedVersions
   ```

1. 使用 [publish-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-version.html) 命令發佈函數版本。

   ```
   aws lambda publish-version \
     --function-name my-function
   ```

1. 執行 [get-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-function-configuration.html) 命令並指定版本編號，確認已為函數版本啟動 SnapStart。以下範例命令指定第 1 版。

   ```
   aws lambda get-function-configuration \
     --function-name my-function:1
   ```

   如果回應顯示 [OptimizationStatus](https://docs.aws.amazon.com/lambda/latest/api/API_SnapStartResponse.html) 為 `On` 且 [State](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html#lambda-GetFunctionConfiguration-response-State) 為 `Active`，便會啟動 SnapStart，且快照可用於指定的函數版本。

   ```
   "SnapStart": { 
       "ApplyOn": "PublishedVersions",
       "OptimizationStatus": "On"
    },
    "State": "Active",
   ```

1. 執行 [invoke](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html) 命令並指定版本來調用函數版本。以下範例調用第 1 版。

   ```
   aws lambda invoke \
     --cli-binary-format raw-in-base64-out \
     --function-name my-function:1 \
     --payload '{ "name": "Bob" }' \
     response.json
   ```

   如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

**建立新函數時啟動 SnapStart**

1. 執行 [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) 命令搭配 **--snap-start** 選項來建立函數。針對 **--role**，請指定[執行角色](lambda-intro-execution-role.md)的 Amazon Resource Name (ARN)。

   ```
   aws lambda create-function \
     --function-name my-function \
     --runtime "java25" \
     --zip-file fileb://my-function.zip \
     --handler my-function.handler \
     --role arn:aws:iam::111122223333:role/lambda-ex \
     --snap-start ApplyOn=PublishedVersions
   ```

1. 使用 [publish-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-version.html) 命令來建立版本。

   ```
   aws lambda publish-version \
     --function-name my-function
   ```

1. 執行 [get-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/get-function-configuration.html) 命令並指定版本編號，確認已為函數版本啟動 SnapStart。以下範例命令指定第 1 版。

   ```
   aws lambda get-function-configuration \
     --function-name my-function:1
   ```

   如果回應顯示 [OptimizationStatus](https://docs.aws.amazon.com/lambda/latest/api/API_SnapStartResponse.html) 為 `On` 且 [State](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html#lambda-GetFunctionConfiguration-response-State) 為 `Active`，便會啟動 SnapStart，且快照可用於指定的函數版本。

   ```
   "SnapStart": { 
        "ApplyOn": "PublishedVersions",
        "OptimizationStatus": "On"
     },
     "State": "Active",
   ```

1. 執行 [invoke](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html) 命令並指定版本來調用函數版本。以下範例調用第 1 版。

   ```
   aws lambda invoke \
     --cli-binary-format raw-in-base64-out \
     --function-name my-function:1 \
     --payload '{ "name": "Bob" }' \
     response.json
   ```

   如果您使用的是第 2 AWS CLI 版，則需要 **cli-binary-format**選項。若要讓此成為預設的設定，請執行 `aws configure set cli-binary-format raw-in-base64-out`。若要取得更多資訊，請參閱*《AWS Command Line Interface 使用者指南第 2 版》*中 [AWS CLI 支援的全域命令列選項](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

## 啟動 SnapStart (API)
<a name="snapshot-api"></a>

**啟動 SnapStart**

1. 執行以下任意一項：
   + 使用 [CreateFunction](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html) API 動作搭配 [SnapStart](https://docs.aws.amazon.com/lambda/latest/api/API_SnapStart.html) 參數，建立啟動 SnapStart 的新函數。
   + 使用 [UpdateFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_UpdateFunctionConfiguration.html) 動作搭配 SnapStart 參數，為現有函數啟動 [SnapStart](https://docs.aws.amazon.com/lambda/latest/api/API_SnapStart.html)。

1. 使用 [PublishVersion](https://docs.aws.amazon.com/lambda/latest/api/API_PublishVersion.html) 動作發佈函數版本。Lambda 會初始化程式碼、建立初始化執行環境的快照，然後快取快照以實現低延遲存取。

1. 使用 [GetFunctionConfiguration](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html) 動作，確認已為函數版本啟動 SnapStart。指定版本編號以確認已為該版本啟動 SnapStart。如果回應顯示 [OptimizationStatus](https://docs.aws.amazon.com/lambda/latest/api/API_SnapStartResponse.html) 為 `On` 且 [State](https://docs.aws.amazon.com/lambda/latest/api/API_GetFunctionConfiguration.html#lambda-GetFunctionConfiguration-response-State) 為 `Active`，便會啟動 SnapStart，且快照可用於指定的函數版本。

   ```
   "SnapStart": { 
           "ApplyOn": "PublishedVersions",
           "OptimizationStatus": "On"
        },
        "State": "Active",
   ```

1. 使用 [Invoke](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html) 動作調用函數版本。

## Lambda SnapStart 和函數狀態
<a name="snapstart-function-states"></a>

使用 SnapStart時，可能會出現下列函數狀態。

**待定**  
Lambda 正在初始化您的程式碼，並擷取初始化執行環境的快照。在函數上操作的任何調用或其他 API 動作都會失敗。

**作用中**  
快照建立完成，您可以調用函數。若要使用 SnapStart，您必須調用已發佈的函數版本，而不是未發佈版本 (\$1LATEST)。

**非作用中**  
當 Lambda 定期重新產生函式快照以套用軟體更新時，可能會出現 `Inactive` 狀態。在此執行個體中，如果函數無法初始化，則函數會進入`Inactive`狀態。  
對於使用 Java 執行時期的函式，若已有 14 天未調用快照，Lambda 會將其刪除。如果您在 14 天後調用函數版本，Lambda 會傳回 `SnapStartNotReadyException` 回應並開始初始化新快照。等待函數版本進入 `Active` 狀態，然後再次調用它。

**失敗**  
Lambda 在執行初始化程式碼或建立快照時發生錯誤。

## 更新快照
<a name="update-snapshot"></a>

Lambda 會為每個已發佈的函數版本建立快照。若要更新快照，請發佈新函數版本。

## 使用 SnapStart AWS SDKs
<a name="snapstart-credentials"></a>

若要從函數進行 AWS SDK 呼叫，Lambda 會透過擔任函數的執行角色來產生一組暫時性的登入資料。這些憑證在函數調用期間可當成環境變數使用。您不需要直接在程式碼中提供 SDK 的憑證。根據預設，憑證提供者鏈會依序檢查您可以設定憑證的每個位置，並選擇第一個可用的位置，通常是環境變數 (`AWS_ACCESS_KEY_ID`、`AWS_SECRET_ACCESS_KEY` 和 `AWS_SESSION_TOKEN`)。

**注意**  
SnapStart 啟動時，Lambda 執行時期會自動使用容器憑證 (`AWS_CONTAINER_CREDENTIALS_FULL_URI` 和 `AWS_CONTAINER_AUTHORIZATION_TOKEN`)，而不是存取金鑰環境變數。這樣可防止憑證在函數還原之前過期。

## 搭配 CloudFormation AWS SAM、 和 使用 SnapStart AWS CDK
<a name="snapstart-cfn-sam"></a>
+ **AWS CloudFormation：**在範本中宣告 [SnapStart](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-snapstart.html) 實體。
+ **AWS Serverless Application Model (AWS SAM)：**宣告範本中的 [SnapStart](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-snapstart) 屬性。
+ **AWS Cloud Development Kit (AWS CDK)：**使用 [SnapStartProperty](https://docs.aws.amazon.com/cdk/api/v2/java/software/amazon/awscdk/services/lambda/CfnFunction.SnapStartProperty.html) 類型。

## 刪除快照
<a name="snapshot-delete"></a>

Lambda 會在發生以下情況時刪除快照：
+ 您刪除了函數或函數版本。
+ (**僅限 Java 執行時期**) 您 14 天內都沒有調用函數版本。連續 14 天都沒有呼叫之後，函數版本會轉換為 [Inactive](#snapstart-function-states) (非作用中) 狀態。如果您在 14 天後調用函數版本，Lambda 會傳回 `SnapStartNotReadyException` 回應並開始初始化新快照。等待函數版本進入 [Active](#snapstart-function-states) (作用中) 狀態，然後再次調用它。

根據一般資料保護規範 (GDPR)，Lambda 會移除與已刪除快照相關聯的所有資源。

# 使用 Lambda SnapStart 處理唯一性
<a name="snapstart-uniqueness"></a>

SnapStart 函數上的呼叫擴展時，Lambda 會使用單一初始化快照來恢復多個執行環境。如果您的初始化程式碼會產生包含在快照中的唯一內容，則在跨執行環境中重複使用該內容時，該內容可能不是唯一的。若要在使用 SnapStart 時保持唯一性，您必須在初始化後產生唯一的內容。這包括唯一 ID、唯一密碼，以及用來產生偽隨機性的熵。

以下是維持程式碼唯一性的建議最佳實務。對於 Java 函數，Lambda 還提供開放原始碼 [SnapStart 掃描工具](#snapstart-scanning)，協助檢查確保唯一性的程式碼。如果您在初始化階段產生唯一資料，便可使用[執行階段掛鉤](snapstart-runtime-hooks.md)來還原唯一性。使用執行階段掛鉤，您可以在 Lambda 建立快照前執行特定程式碼，或在 Lambda 從快照恢復函數後立即執行特定程式碼。

## 避免儲存初始化期間依賴唯一性的狀態
<a name="snapstart-caching-unique"></a>

在函數的[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)，請避免快取預定為唯一的資料，例如產生用於日誌記錄的唯一 ID 或設定隨機函數的種子。相反地，建議您在函數處理常式中產生唯一的資料或設定隨機函數的種子，或使用[執行時期勾點](snapstart-runtime-hooks.md)進行這些操作。

以下程式碼範例示範如何在函數處理常式中產生 UUID。

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

**Example - 在函數處理常式中產生唯一 ID**  

```
import java.util.UUID;
  public class Handler implements RequestHandler<String, String> {
    private static UUID uniqueSandboxId = null;
    @Override
    public String handleRequest(String event, Context context) {
      if (uniqueSandboxId == null)
        uniqueSandboxId = UUID.randomUUID();
      System.out.println("Unique Sandbox Id: " + uniqueSandboxId);
      return "Hello, World!";
    }
  }
```

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

**Example - 在函數處理常式中產生唯一 ID**  

```
import json
import random
import time

unique_number = None

def lambda_handler(event, context):
    seed = int(time.time() * 1000) 
    random.seed(seed)
    global unique_number
    if not unique_number:
        unique_number = random.randint(1, 10000)
        
    print("Unique number: ", unique_number)
    
    return "Hello, World!"
```

------
#### [ .NET ]

**Example - 在函數處理常式中產生唯一 ID**  

```
namespace Example;
public class SnapstartExample
{
    private Guid _myExecutionEnvironmentGuid;
    public SnapstartExample()
    {
        // This GUID is set for non-restore use cases, such as testing or if SnapStart is turned off
        _myExecutionEnvironmentGuid = new Guid();
        // Register the method which will run after each restore. You may need to update Amazon.Lambda.Core to see this
        Amazon.Lambda.Core.SnapshotRestore.RegisterAfterRestore(MyAfterRestore);
    }

    private ValueTask MyAfterRestore()
    {
        // After restoring this snapshot to a new execution environment, update the GUID
        _myExecutionEnvironmentGuid = new Guid();
        return ValueTask.CompletedTask;
    }

    public string Handler()
    {
        return $"Hello World! My Execution Environment GUID is {_myExecutionEnvironmentGuid}";
    }
}
```

------

## 使用密碼編譯安全的虛擬隨機數產生器 (CSPRNGs)
<a name="snapstart-csprng"></a>

如果您的應用程式依賴隨機性，建議您使用密碼編譯安全隨機數產生器 (CSPRNGs)。除了 OpenSSL 1.0.2 之外，Lambda 受管執行時期還包含以下內建 CSPRNG：
+ **Java：**`java.security.SecureRandom`
+ **Python：**`random.SystemRandom`
+ **.NET：**`System.Security.Cryptography.RandomNumberGenerator`

此軟體總是會從 `/dev/random` 或 `/dev/urandom` 取得隨機數，也會透過 SnapStart 保持隨機性。

AWS 從下表指定的最低版本開始，密碼編譯程式庫會自動維持 SnapStart 的隨機性。如果您在 Lambda 函數中使用這些程式庫，請確定您使用以下最低版本或更新版本：


****  

| 程式庫 | 支援的最低版本 (x86) | 支援的最低版本 (ARM) | 
| --- | --- | --- | 
| AWS libcrypto (AWS-LC) |  1.16.0  |  1.30.0  | 
| AWS libcrypto FIPS |  2.0.13  | 2.0.13 | 

如果您透過以下程式庫將上述密碼編譯程式庫封裝為 Lambda 函數的遞移相依項，請務必使用以下最低版本或更新版本：


****  

| 程式庫 | 支援的最低版本 (x86) | 支援的最低版本 (ARM) | 
| --- | --- | --- | 
| AWS SDK for Java 2.x |  2.23.20  |  2.26.12  | 
| AWS Java 的常見執行期 |  0.29.8  |  0.29.25  | 
| Amazon Corretto Crypto Provider |  2.4.1  | 2.4.1 | 
| Amazon Corretto Crypto Provider FIPS |  2.4.1  | 2.4.1 | 

以下範例示範如何使用 CSPRNG 來保證唯一數字序列，即使從快照還原函數也是如此。

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

**Example – java.security.SecureRandom**  

```
import java.security.SecureRandom;
  public class Handler implements RequestHandler<String, String> {
    private static SecureRandom rng = new SecureRandom();
    @Override
    public String handleRequest(String event, Context context) {
      for (int i = 0; i < 10; i++) {
        System.out.println(rng.next());
      }
      return "Hello, World!";
    }
  }
```

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

**Example ：random.SystemRandom**  

```
import json
import random

secure_rng = random.SystemRandom()

def lambda_handler(event, context):
    random_numbers = [secure_rng.random() for _ in range(10)]
    
    for number in random_numbers:
        print(number)
    
    return "Hello, World!"
```

------
#### [ .NET ]

**Example ：RandomNumberGenerator**  

```
using Amazon.Lambda.Core;
using System.Security.Cryptography;
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace DotnetSecureRandom;

public class Function
{
    public string FunctionHandler()
    {
        using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
        {
            byte[] randomUnsignedInteger32Bytes = new byte[4];
            for (int i = 0; i < 10; i++)
            {
                rng.GetBytes(randomUnsignedInteger32Bytes);
                int randomInt32 = BitConverter.ToInt32(randomUnsignedInteger32Bytes, 0);
                Console.WriteLine("{0:G}", randomInt32);
            }
        }
        return "Hello World!";
    }
}
```

------

## SnapStart 掃描工具 (僅限 Java)
<a name="snapstart-scanning"></a>

Lambda 提供 Java 掃描工具，可協助檢查確保唯一性的程式碼。SnapStart 掃描工具是一種開放原始碼 [SpotBugs](https://spotbugs.github.io/) 外掛程式，可針對一組規則執行靜態分析。掃描工具有助於識別可能會破壞有關唯一性假設的潛在程式碼實作。如需安裝指示和掃描工具執行的檢查清單，請參閱 GitHub 上的 [aws-lambda-snapstart-java-rules](https://github.com/aws/aws-lambda-snapstart-java-rules) 儲存庫。

若要進一步了解如何使用 SnapStart 處理唯一性，請參閱 AWS 運算部落格上的[使用 AWS Lambda SnapStart 更快速啟動](https://aws.amazon.com/blogs/compute/starting-up-faster-with-aws-lambda-snapstart/)。

# 在 Lambda 函數快照之前或之後實作程式碼
<a name="snapstart-runtime-hooks"></a>

您可以在 Lambda 建立快照之前或 Lambda 從快照恢復函數之後，使用執行階段掛鉤來實作程式碼。執行時期勾點有許多用途，包括：
+ **清除和初始化：**建立快照之前，您可以使用執行時期勾點來執行清除或資源釋放操作。還原快照後，您可以使用執行時期勾點重新初始化快照中未擷取的任何資源或狀態。
+ **動態組態：**您可以在建立快照之前或還原之後，使用執行時期勾點動態更新組態或其他中繼資料。如果函數需要適應執行時期環境的變更，這很有用。
+ **外部整合：**您可以使用執行時期勾點與外部服務或系統整合，作為檢查點和還原程序的一部分，藉此完成傳送通知或更新外部狀態等操作。
+ **效能調校：**您可以使用執行時期勾點來微調函數的啟動順序，例如預先載入相依項。如需更多詳細資訊，請參閱 [效能調校](snapstart-best-practices.md#snapstart-tuning)。

以下幾頁說明如何針對您偏好的執行時期實作執行時期勾點。

**Topics**
+ [Java](snapstart-runtime-hooks-java.md)
+ [Python](snapstart-runtime-hooks-python.md)
+ [.NET](snapstart-runtime-hooks-dotnet.md)

# Lambda SnapStart 執行時期勾點 (Java)
<a name="snapstart-runtime-hooks-java"></a>

您可以在 Lambda 建立快照之前或 Lambda 從快照恢復函數之後，使用執行階段掛鉤來實作程式碼。執行階段掛鉤可做為開放原始碼 Coordinated Restore at Checkpoint (CRaC) 專案的一部分使用。目前正在針對 [Java 開發套件 (OpenJDK)](https://wiki.openjdk.org/display/crac) 開發 CRaC。如需如何搭配參考應用程式使用 CRaC 的範例，請參閱 GitHub 上的 [CRaC](https://github.com/CRaC/docs/blob/master/STEP-BY-STEP.md) 儲存庫。CRaC 使用三個主要元素：
+ `Resource` - 具有兩種方法 (`beforeCheckpoint()` 和 `afterRestore()`) 的介面。使用這些方法來實作您想在快照建立之前和還原之後執行的程式碼。
+ `Context <R extends Resource>` - 若要接收檢查點和還原的通知，必須透過 `Context` 註冊 `Resource`。
+ `Core` - 協調服務，透過靜態方法 `Core.getGlobalContext()` 提供預設的全域 `Context`。

如需 `Context` 和 `Resource` 的詳細資訊，請參閱 CRaC 文件中的[套件 org.crac](https://javadoc.io/doc/io.github.crac/org-crac/latest/index.html)。

使用下列步驟，透過 [org.crac 套件](https://github.com/CRaC/org.crac)實作執行階段掛鉤。Lambda 執行階段包含自訂的 CRaC 內容實作，可在檢查點之前和還原之後呼叫執行階段掛鉤。

## 執行時期勾點註冊和執行
<a name="runtime-hooks-registration-java"></a>

Lambda 執行執行時期勾點的順序取決於勾點的註冊順序。註冊順序遵循程式碼中的匯入、定義或執行順序。
+ `beforeCheckpoint()`：依與註冊順序相反的順序執行
+ `afterRestore()`：依註冊順序執行

確定已正確匯入所有已註冊的勾點，並包含在函數的程式碼中。如果您在單獨的檔案或模組中註冊執行時期勾點，則必須確保直接匯入相關模組，或將其作為較大套件的一部分匯入函數的處理常式檔案中。如果未在函數處理常式中匯入相關檔案或模組，則 Lambda 會忽略相關執行時期勾點。

**注意**  
Lambda 建立快照時，初始化程式碼最多可能會執行 15 分鐘。時間上限為 130 秒或[設定的函數逾時](configuration-timeout.md) (最長 900 秒)，以較高者為準。您的 `beforeCheckpoint()` 執行時間掛鉤會計入初始化程式碼時間限制。Lambda 還原快照時，執行時期必須載入，且 `afterRestore()` 執行時期勾點必須在逾時限制 (10 秒) 內完成。否則，您將收到 SnapStartTimeoutException 訊息。

## 步驟 1：更新建置組態
<a name="runtime-hooks-java-update-build"></a>

將 `org.crac` 相依性新增到建置組態。以下範例使用 Gradle。如需其他建置系統的範例，請參閱 [Apache Maven 文件](https://search.maven.org/artifact/io.github.crac/org-crac/0.1.3/jar)。

```
dependencies {
    compile group: 'com.amazonaws', name: 'aws-lambda-java-core', version: '1.2.1'
    # All other project dependecies go here:
    # ...
    # Then, add the org.crac dependency:
 implementation group: 'org.crac', name: 'crac', version: '1.4.0'
}
```

## 步驟 2：更新 Lambda 處理常式
<a name="runtime-hooks-java-update-handler"></a>

Lambda 函數*處理常式*是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時，Lambda 會執行處理常式方法。函數會執行，直到處理常式傳回回應、結束或逾時為止。

如需詳細資訊，請參閱[在 Java 中定義 Lambda 函數處理常式](java-handler.md)。

以下處理常式範例示範如何在檢查點之前 (`beforeCheckpoint()`) 和還原之後 (`afterRestore()`) 執行程式碼。此處理常式也會向執行階段管理的全域 `Context` 註冊 `Resource`。

**注意**  
Lambda 建立快照時，初始化程式碼最多可能會執行 15 分鐘。時間上限為 130 秒或[設定的函數逾時](configuration-timeout.md) (最長 900 秒)，以較高者為準。您的 `beforeCheckpoint()` 執行時間掛鉤會計入初始化程式碼時間限制。Lambda 還原快照時，執行階段 (JVM) 必須載入，且 `afterRestore()` 執行階段掛鉤必須在逾時限制 (10 秒) 內完成。否則，您將收到 SnapStartTimeoutException 訊息。

```
...
  import org.crac.Resource;
  import org.crac.Core;
  ... 
public class CRaCDemo implements RequestStreamHandler, Resource {
    public CRaCDemo() {
      Core.getGlobalContext().register(this);
    }
    public String handleRequest(String name, Context context) throws IOException {
      System.out.println("Handler execution");
      return "Hello " + name;
    }
    @Override
    public void beforeCheckpoint(org.crac.Context<? extends Resource> context)
        throws Exception {
      System.out.println("Before checkpoint");
    }
    @Override
    public void afterRestore(org.crac.Context<? extends Resource> context)
        throws Exception {
      System.out.println("After restore");
```

`Context` 僅會對已註冊物件維持 [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/WeakReference.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ref/WeakReference.html)。如果 [https://javadoc.io/static/io.github.crac/org-crac/0.1.3/org/crac/Resource.html](https://javadoc.io/static/io.github.crac/org-crac/0.1.3/org/crac/Resource.html) 是回收的垃圾，則執行階段掛鉤程式不會執行。您的程式碼必須維持對 `Resource` 的強式參考，才能保證執行階段掛鉤會執行。

以下是須避免的兩個模式範例：

**Example - 沒有強式參考的物件**  

```
Core.getGlobalContext().register( new MyResource() );
```

**Example - 匿名類別的物件**  

```
Core.getGlobalContext().register( new Resource() {
   
   @Override
   public void afterRestore(Context<? extends Resource> context) throws Exception {
    // ...
   }
   
   @Override
   public void beforeCheckpoint(Context<? extends Resource> context) throws Exception {
    // ...
   }

} );
```

而是維持強式參考。在下列範例中，已註冊的資源不是回收的垃圾，且執行階段掛鉤會一致地執行。

**Example - 有強式參考的物件**  

```
Resource myResource = new MyResource(); // This reference must be maintained to prevent the registered resource from being garbage collected
Core.getGlobalContext().register( myResource );
```

# Lambda SnapStart 執行時期勾點 (Python)
<a name="snapstart-runtime-hooks-python"></a>

您可以在 Lambda 建立快照之前或 Lambda 從快照恢復函數之後，使用執行階段掛鉤來實作程式碼。Python 執行時期勾點作為 [Snapshot Restore for Python library](https://pypi.org/project/snapshot-restore-py/) 的一部分提供，該程式庫包含在 Python 受管執行時期中。此程式庫提供兩個裝飾項目，可用於定義執行時期勾點：
+ `@register_before_snapshot`：用於您要在 Lambda 建立快照之前執行的函數。
+ `@register_after_restore`：用於您要在 Lambda 從快照恢復函數時執行的函數。

您也可以使用以下方法來註冊執行時期勾點的可呼叫項：
+ `register_before_snapshot(func, *args, **kwargs)`
+ `register_after_restore(func, *args, **kwargs)`

## 執行時期勾點註冊和執行
<a name="runtime-hooks-registration-python"></a>

Lambda 執行執行時期勾點的順序取決於勾點的註冊順序：
+ 快照之前：依與註冊順序相反的順序執行
+ 快照之後：依註冊順序執行

執行時期勾點註冊的順序取決於您如何定義勾點。使用裝飾項目 (`@register_before_snapshot` 和 `@register_after_restore`) 時，註冊順序會遵循程式碼中的匯入、定義或執行順序。如果您需要對註冊順序進行更多控制，請使用 `register_before_snapshot()` 和 `register_after_restore()` 方法，而不要使用裝飾項目。

確定已正確匯入所有已註冊的勾點，並包含在函數的程式碼中。如果您在單獨的檔案或模組中註冊執行時期勾點，則必須確保直接匯入相關模組，或將其作為較大套件的一部分匯入函數的處理常式檔案中。如果未在函數處理常式中匯入相關檔案或模組，則 Lambda 會忽略相關執行時期勾點。

**注意**  
Lambda 建立快照時，初始化程式碼最多可能會執行 15 分鐘。時間上限為 130 秒或[設定的函數逾時](configuration-timeout.md) (最長 900 秒)，以較高者為準。您的 `@register_before_snapshot` 執行時間掛鉤會計入初始化程式碼時間限制。Lambda 還原快照時，執行時期必須載入，且 `@register_after_restore` 執行時期勾點必須在逾時限制 (10 秒) 內完成。否則，您將收到 SnapStartTimeoutException 訊息。

## 範例
<a name="runtime-hooks-python-code-sample"></a>

以下處理常式範例示範如何在檢查點之前 (`@register_before_snapshot`) 和還原之後 (`@register_after_restore`) 執行程式碼。

```
from snapshot_restore_py import register_before_snapshot, register_after_restore

def lambda_handler(event, context):
    # Handler code

@register_before_snapshot
def before_checkpoint():
    # Logic to be executed before taking snapshots

@register_after_restore
def after_restore():
    # Logic to be executed after restore
```

如需更多範例，請參閱 AWS GitHub 儲存庫中的 [Snapshot Restore for Python](https://github.com/aws/snapshot-restore-py/tree/main/examples)。

# Lambda SnapStart 執行時期勾點 (.NET)
<a name="snapstart-runtime-hooks-dotnet"></a>

您可以在 Lambda 建立快照之前或 Lambda 從快照恢復函數之後，使用執行階段掛鉤來實作程式碼。[Amazon.Lambda.Core](https://www.nuget.org/packages/Amazon.Lambda.Core) 套件 (2.5.0 版或更新版本) 提供 .NET 執行時期勾點。此程式庫提供兩種定義執行時期勾點的方法：
+ `RegisterBeforeSnapshot()`：建立快照前執行的程式碼
+ `RegisterAfterSnapshot()`：從快照恢復函數後執行的程式碼

**注意**  
如果使用的是[適用於 .NET 的 Lambda Annotations 架構](csharp-handler.md#csharp-handler-annotations)，請升級至 [Amazon.Lambda.Annotations](https://www.nuget.org/packages/Amazon.Lambda.Annotations) 1.6.0 版或更新版本，以確保與 SnapStart 的相容性。

## 執行時期勾點註冊和執行
<a name="runtime-hooks-registration-dotnet"></a>

在初始化程式碼中註冊勾點。根據 Lambda 函數的[執行模型](csharp-handler.md#csharp-handler-setup)考慮下列準則：
+ 對於[可執行的組裝方法](csharp-handler.md#csharp-executable-assembly-handlers)，請在使用 `RunAsync` 啟動 Lambda 引導程序之前註冊勾點。
+ 對於[類別程式庫方法](csharp-handler.md#csharp-class-library-handlers)，請在處理常式類別建構函數中註冊勾點。
+ 對於 [ASP.NET Core 應用程式](csharp-package-asp.md)，請先註冊勾點，再呼叫 `WebApplications.Run` 方法。

若要在 .NET 中註冊 SnapStart 的執行時期勾點，請使用以下方法：

```
Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(BeforeCheckpoint);
Amazon.Lambda.Core.SnapshotRestore.RegisterAfterRestore(AfterCheckpoint);
```

註冊多個勾點類型時，Lambda 執行執行執行時期勾點的順序取決於勾點的註冊順序：
+ `RegisterBeforeSnapshot()`：依與註冊順序相反的順序執行
+ `RegisterAfterSnapshot()`：依註冊順序執行

**注意**  
Lambda 建立快照時，初始化程式碼最多可能會執行 15 分鐘。時間上限為 130 秒或[設定的函數逾時](configuration-timeout.md) (最長 900 秒)，以較高者為準。您的 `RegisterBeforeSnapshot()` 執行時間掛鉤會計入初始化程式碼時間限制。Lambda 還原快照時，執行時期必須載入，且 `RegisterAfterSnapshot()` 執行時期勾點必須在逾時限制 (10 秒) 內完成。否則，您將收到 SnapStartTimeoutException 訊息。

## 範例
<a name="runtime-hooks-dotnet-code-sample"></a>

以下函數範例示範如何在檢查點之前 (`RegisterBeforeSnapshot`) 和還原之後 (`RegisterAfterRestore`) 執行程式碼。

```
public class SampleClass
{
    public SampleClass()
    {
        Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(BeforeCheckpoint);
        Amazon.Lambda.Core.SnapshotRestore.RegisterAfterRestore(AfterCheckpoint);
    }

    private ValueTask BeforeCheckpoint()
    {
        // Add logic to be executed before taking the snapshot
        return ValueTask.CompletedTask;
    }

    private ValueTask AfterCheckpoint()
    {
        // Add logic to be executed after restoring the snapshot
        return ValueTask.CompletedTask;
    }

    public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        // Add business logic

        return new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
    }
}
```

# 監控 Lambda SnapStart
<a name="snapstart-monitoring"></a>

您可 Lambda 使用 Amazon CloudWatch、AWS X-Ray 和 [使用遙測 API 即時存取延伸功能的遙測資料](telemetry-api.md) 來監控 Lambda SnapStart 函數。

**注意**  
`AWS_LAMBDA_LOG_GROUP_NAME` 和 `AWS_LAMBDA_LOG_STREAM_NAME` [環境變數](configuration-envvars.md#configuration-envvars-runtime)無法在 Lambda SnapStart 函數中使用。

## 了解 SnapStart 的記錄和計費行為
<a name="snapstart-cloudwatch"></a>

SnapStart 函數的 [CloudWatch 日誌串流](monitoring-cloudwatchlogs.md)格式有一些差異：
+ **初始化日誌**：建立新的執行環境時，`REPORT` 不會含有 `Init Duration` 欄位。這是因為 Lambda 會在您建立版本時初始化 SnapStart 函數，而非在函數調用期間。若為 SnapStart 函數，`Init Duration` 欄位位於 `INIT_REPORT` 記錄中。此記錄會顯示 [初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib) 的持續時間詳細資訊，包括任何 `beforeCheckpoint` [執行階段掛鉤](snapstart-runtime-hooks.md)的持續時間。
+ **調用日誌**：建立新的執行環境時，`REPORT` 會含有 `Restore Duration` 和 `Billed Restore Duration` 欄位：
  + `Restore Duration`：Lambda 還原快照、載入執行時期和執行任何還原後[執行時期勾點](snapstart-runtime-hooks.md)所需的時間。還原快照的程序可能包括在 MicroVM 以外的活動上花費的時間。此時間在 `Restore Duration` 中報告。
  + `Billed Restore Duration`：Lambda 載入執行時期和執行任何還原後[執行時期勾點](snapstart-runtime-hooks.md)所需的時間。

**注意**  
如同所有 Lambda 函數一樣，持續時間費用適用於函數處理常式中執行的程式碼。對於 SnapStart 函數，持續時間費用也適用於在處理常式之外宣告的初始化程式碼、執行時期進行載入所花的時間以及在[執行時期勾點](snapstart-runtime-hooks.md)中執行的任何程式碼。

冷啟動持續時間是 `Restore Duration` \$1 `Duration` 的總和。

下列 Lambda Insights 查詢範例傳回了 SnapStart 函數的延遲百分位數。如需 Lambda Insights 查詢的詳細資訊，請參閱：[使用查詢故障排除函式的範例工作流程](monitoring-insights.md#monitoring-insights-queries)。

```
filter @type = "REPORT"
  | parse @log /\d+:\/aws\/lambda\/(?<function>.*)/
  | parse @message /Restore Duration: (?<restoreDuration>.*?) ms/
  | stats
count(*) as invocations,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 50) as p50,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 90) as p90,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 99) as p99,
pct(@duration+coalesce(@initDuration,0)+coalesce(restoreDuration,0), 99.9) as p99.9
group by function, (ispresent(@initDuration) or ispresent(restoreDuration)) as coldstart
  | sort by coldstart desc
```

## 適用於 SnapStart 的 X-Ray 作用中追蹤
<a name="snapstart-xray"></a>

您可以使用 [X-Ray](services-xray.md) 來追蹤 Lambda SnapStart 函數的請求。SnapStart 函數的 X-Ray 子區段有一些差異：
+ SnapStart 函數沒有 `Initialization` 子區段。
+ `Restore` 子區段會顯示 Lambda 還原快照、載入執行時期和執行任何還原後[執行時期勾點](snapstart-runtime-hooks.md)所需的時間。還原快照的程序可能包括在 MicroVM 以外的活動上花費的時間。此時間在 `Restore` 子區段中報告。您不需要為在 MicroVM 外還原快照所花費的時間付費。

## SnapStart 的遙測 API 事件
<a name="snapstart-telemetry"></a>

Lambda 會將下列 SnapStart 事件傳送至 [遙測 API](telemetry-api.md)：
+ [`platform.restoreStart`](telemetry-schema-reference.md#platform-restoreStart) - 顯示 [`Restore` 階段](lambda-runtime-environment.md#runtimes-lifecycle-restore)開始的時間。
+ [`platform.restoreRuntimeDone`](telemetry-schema-reference.md#platform-restoreRuntimeDone) - 顯示 `Restore` 階段是否成功。執行階段傳送 `restore/next` 執行階段 API 請求時，Lambda 會產生此訊息。可能的狀態有三種：成功、失敗和逾時。
+ [`platform.restoreReport`](telemetry-schema-reference.md#platform-restoreReport) - 顯示 `Restore` 階段持續的時間長度，以及您須為此階段支付的費用。

## Amazon API Gateway 和函數 URL 指標
<a name="snapstart-metrics"></a>

如果您是[使用 API Gateway](services-apigateway.md) 建立 Web API，便可以使用 [IntegrationLatency](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-metrics-and-dimensions.html) 指標來測量端對端延遲 (API Gateway 將請求轉送至後端與收到後端回應之間的時間)。

如果您使用的是 [Lambda 函數 URL](urls-configuration.md)，則可以使用 [UrlRequestLatency](urls-monitoring.md) 指標來測量端對端延遲 (函數 URL 收到請求與函數 URL 傳回回應之間的時間)。

# Lambda SnapStart 的安全模型
<a name="snapstart-security"></a>

Lambda SnapStart 支援靜態加密。Lambda 使用 AWS KMS key 來加密快照。預設情況下，Lambda 使用 AWS 受管金鑰。如果此預設行為符合您的工作流程，您便不需要設定其他項目。若不符合，您可以在 [create-function](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/create-function.html) 或 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) 命令中使用 `--kms-key-arn` 選項來提供 AWS KMS 客戶管理的金鑰。這麼做可控制 KMS 金鑰的輪換或滿足貴組織對管理 KMS 金鑰的要求。客戶受管的金鑰會產生標準的 AWS KMS 費用。如需詳細資訊，請參閱 [AWS Key Management Service 定價](https://aws.amazon.com/kms/pricing/)。

當您刪除 SnapStart 函數或函數版本時，對該函數或函數版本發出的所有 `Invoke` 要求都會失敗。根據一般資料保護規範 (GDPR)，Lambda 會移除與已刪除快照相關聯的所有資源。

# 最大化 Lambda SnapStart 效能
<a name="snapstart-best-practices"></a>

**Topics**
+ [

## 效能調校
](#snapstart-tuning)
+ [

## 網路最佳實務
](#snapstart-networking)

## 效能調校
<a name="snapstart-tuning"></a>

若要充分利用 SnapStart 的優勢，請針對您的執行時期考慮下列程式碼最佳化建議。

**注意**  
SnapStart 搭配大規模函數調用使用時效果最佳。不常調用的函數效能改進效果可能不會相同。

### Java
<a name="snapstart-tuning-java"></a>

為了充分利用 SnapStart 的優勢，建議您在初始化程式碼 (而不是函數處理常式) 中預先載入會導致啟動延遲的相依項和初始化資源。這會將與大量類別載入相關聯的延遲移出調用路徑，進而透過 SnapStart 最佳化啟動效能。

如果您無法在初始化期間預先載入相依項和初始化資源，建議您使用虛擬調用預先載入它們。若要執行此作業，請從 AWS Labs GitHub 儲存庫上的[寵物存放區函數](https://github.com/awslabs/aws-serverless-java-container/tree/main/samples/spring/pet-store)更新函數處理常式程式碼，如下列範例所示。

```
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
  static {
      try {
          handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);

          // Use the onStartup method of the handler to register the custom filter
          handler.onStartup(servletContext -> {
              FilterRegistration.Dynamic registration = servletContext.addFilter("CognitoIdentityFilter", CognitoIdentityFilter.class);
              registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
          });

          // Send a fake Amazon API Gateway request to the handler to load classes ahead of time
          ApiGatewayRequestIdentity identity = new ApiGatewayRequestIdentity();
          identity.setApiKey("foo");
          identity.setAccountId("foo");
          identity.setAccessKey("foo");

          AwsProxyRequestContext reqCtx = new AwsProxyRequestContext();
          reqCtx.setPath("/pets");
          reqCtx.setStage("default");
          reqCtx.setAuthorizer(null);
          reqCtx.setIdentity(identity);

          AwsProxyRequest req = new AwsProxyRequest();
          req.setHttpMethod("GET");
          req.setPath("/pets");
          req.setBody("");
          req.setRequestContext(reqCtx);

          Context ctx = new TestContext();
          handler.proxy(req, ctx);


      } catch (ContainerInitializationException e) {
          // if we fail here. We re-throw the exception to force another cold start
          e.printStackTrace();
          throw new RuntimeException("Could not initialize Spring framework", e);
      }
  }
```

### Python
<a name="snapstart-tuning-python"></a>

若要充分利用 SnapStart 的優勢，在編寫 Python 函數時應重視高效率程式碼組織和資源管理。一般而言，應在[初始化階段](lambda-runtime-environment.md#runtimes-lifecycle-ib)執行繁重的運算任務。這種方法會將耗時的作業移出調用路徑，進而改善函數的整體效能。為協助您有效實作此策略，我們提供以下最佳實務建議：
+ 在函數處理常式外部匯入相依項。
+ 在處理常式外部建立 `boto3` 執行個體。
+ 在調用處理常式之前初始化靜態資源或組態。
+ 請考慮使用快照前[執行時期勾點](snapstart-runtime-hooks-python.md)處理資源密集型任務，例如下載外部檔案、預先載入 Django 等架構，或載入機器學習模型。

**Example ：針對 SnapStart 最佳化 Python 函數**  

```
# Import all dependencies outside of Lambda handler
from snapshot_restore_py import register_before_snapshot
import boto3
import pandas
import pydantic

# Create S3 and SSM clients outside of Lambda handler
s3_client = boto3.client("s3")

# Register the function to be called before snapshot
@register_before_snapshot
def download_llm_models():
    # Download an object from S3 and save to tmp
    # This files will persist in this snapshot
    with open('/tmp/FILE_NAME', 'wb') as f:
        s3_client.download_fileobj('amzn-s3-demo-bucket', 'OBJECT_NAME', f)
    ...

def lambda_handler(event, context):
    ...
```

### .NET
<a name="snapstart-tuning-dotnet"></a>

若要減少即時 (JIT) 編譯和組裝載入時間，請考慮從 `RegisterBeforeCheckpoint` [執行時期勾點](snapstart-runtime-hooks-dotnet.md)調用函數處理常式。由於 .NET 分層編譯的運作方式，多次調用處理常式可獲得最佳結果，如以下範例所示。

**重要**  
請確定虛擬函數調用不會產生非預期的副作用，例如啟動商業交易。

**Example**  

```
public class Function
{
    public Function()
    {
        Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(FunctionWarmup);
    }

    // Warmup method that calls the function handler before snapshot to warm up the .NET code and runtime.
    // This speeds up future cold starts after restoring from a snapshot.

    private async ValueTask FunctionWarmup()
    {
        var request = new APIGatewayProxyRequest
        {
            Path = "/heathcheck",
            HttpMethod = "GET"
        };

        for (var i = 0; i < 10; i++)
        {
            await FunctionHandler(request, null);
        }
    }

    public async Task<APIGatewayProxyResponse> FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        //
        // Process HTTP request
        // 

        var response = new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
        
        return await Task.FromResult(response);
    }
}
```

## 網路最佳實務
<a name="snapstart-networking"></a>

Lambda 從快照恢復函數時，無法保證函數在初始化階段建立的連線狀態。在大多數情況下， AWS 軟體開發套件建立的網路連線會自動恢復。針對其他連線，建議遵循最佳實務操作。

**重新建立網路連線**  
函數從快照恢復時，請務必重新建立網路連線。建議您在函數處理常式中重新建立網路連線。您也可以使用還原後[執行時期勾點](snapstart-runtime-hooks.md)。

**請勿使用主機名做為唯一的執行環境識別符**  
建議您不要使用 `hostname` 將執行環境識別為應用程式中唯一的節點或容器。對於 SnapStart，會使用單一快照做為多個執行環境的初始狀態。所有執行環境對 `InetAddress.getLocalHost()` (Java)、`socket.gethostname()` (Python) 和 `Dns.GetHostName()` (.NET) 都會傳回相同的 `hostname` 值。如果應用程式需要唯一的執行環境識別或 `hostname` 值，建議您在函數處理常式中產生唯一的 ID。或者，使用還原後[執行時期勾點](snapstart-runtime-hooks.md)來產生唯一的 ID，然後使用這個唯一 ID 做為執行環境的識別符。

**避免將連線繫結至固定來源連接埠**  
建議您避免將網路連線繫結至固定來源連接埠。函數從快照恢復時連線會重新建立，而繫結至固定來源連接埠的網路連線可能會失敗。

**避免使用 Java DNS 快取**  
Lambda 函數已快取 DNS 回應。如果您透過 SnapStart 使用其他 DNS 快取，則當函數從快照恢復，可能會發生連線逾時的情況。

`java.util.logging.Logger` 類別可以間接啟用 JVM DNS 快取。若要覆寫預設設定，請先將 [networkaddress.cache.ttl](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/InetAddress.html#inetaddress-caching-heading) 設定為 0，再初始化 `logger`。範例：

```
public class MyHandler {
  // first set TTL property
  static{
   java.security.Security.setProperty("networkaddress.cache.ttl" , "0");
  }
 // then instantiate logger
  var logger = org.apache.logging.log4j.LogManager.getLogger(MyHandler.class);
}
```

為防止 Java 11 執行時期出現 `UnknownHostException` 失敗，建議將 `networkaddress.cache.negative.ttl` 設定為 0。在 Java 17 和更新版本的執行時期中，則不需要此步驟。您可以使用 `AWS_LAMBDA_JAVA_NETWORKADDRESS_CACHE_NEGATIVE_TTL=0` 環境變數為 Lambda 函數設定此屬性。

停用 JVM DNS 快取並不會停用 Lambda 的受管 DNS 快取。

# 對 Lambda 函數的 SnapStart 錯誤進行故障診斷
<a name="snapstart-troubleshooting"></a>

此頁面說明如何解決使用 Lambda SnapStart 時發生的常見問題，包括快照建立錯誤、逾時錯誤和內部服務錯誤。

## SnapStartNotReadyException
<a name="snapstartnotreadyexception"></a>

**錯誤：**呼叫 Invoke20150331 操作時發生錯誤 (SnapStartNotReadyException)：Lambda 正在初始化函數。一旦函數狀態變為「作用中」，即可進行調用。

### 常見原因
<a name="snapstartnotreadyexception-cause"></a>

當嘗試調用處於`Inactive`[狀態](snapstart-activate.md#snapstart-function-states)的函數版本時，便會發生此錯誤。函數版本若超過 14 天未被調用，或在 Lambda 定期回收執行環境時，該函數版本的狀態會變為 `Inactive`

### Resolution
<a name="snapstartnotreadyexception-resolution"></a>

等待函數版本進入 `Active` 狀態，然後再次調用它。

## SnapStartTimeoutException
<a name="snapstart-invocation-failure"></a>

**問題：**當嘗試調用 SnapStart 函數版本時遇到 `SnapStartTimeoutException` 錯誤。

### 常見原因
<a name="snapstart-invocation-failure-cause"></a>

在[還原](lambda-runtime-environment.md#runtimes-lifecycle-restore)階段，Lambda 會還原 Java 執行時期，並執行任何還原後[執行時期勾點](snapstart-runtime-hooks.md)。如果還原後執行時期勾點執行超過 10 秒，且`Restore`階段逾時，則當您嘗試調用函數時便會出現錯誤。網路連線和憑證問題也可能導致 `Restore` 階段逾時。

### Resolution
<a name="snapstart-invocation-failure-resolution"></a>

檢查函數的 CloudWatch 日誌，看看[還原](lambda-runtime-environment.md#runtimes-lifecycle-restore)階段是否發生了逾時錯誤。確定所有還原後勾點在 10 秒內完成。

**Example CloudWatch 日誌**  

```
{ "cause": "Lambda couldn't restore the snapshot within the timeout limit. (Service: Lambda, Status Code: 408, Request ID: 11a222c3-410f-427c-ab22-931d6bcbf4f2)", "error": "Lambda.SnapStartTimeoutException"}
```

## 500 內部服務錯誤
<a name="snapstart-500-error"></a>

**錯誤：**由於已達到並行快照建立限制，Lambda 無法建立新的快照。

### 常見原因
<a name="snapstart-500-error-cause"></a>

500 錯誤是 Lambda 服務本身的內部錯誤，而不是函數或程式碼的問題。這些錯誤通常是間歇性的。

### Resolution
<a name="snapstart-500-error-resolution"></a>

嘗試再次發布函數版本。

## 401 (未經授權)
<a name="snapstart-401-unauthorized"></a>

**錯誤：**錯誤的工作階段字符或標頭金鑰

### 常見原因
<a name="snapstart-401-unauthorized-cause"></a>

搭配 Lambda SnapStart 使用[AWS Systems Manager 參數存放區和 AWS Secrets Manager 延伸](with-secrets-manager.md)時，會發生此錯誤。

### Resolution
<a name="snapstart-401-unauthorized-resolution"></a>

 AWS Systems Manager 參數存放區和 AWS Secrets Manager 擴充功能與 SnapStart 不相容。延伸項目會產生登入資料，以便在函數初始化 AWS Secrets Manager 期間與 通訊，這會導致登入資料錯誤在與 SnapStart 搭配使用時過期。

## UnknownHostException (Java)
<a name="snapstart-dns-caching"></a>

**錯誤：**無法執行 HTTP 請求：`abc.us-east-1.amazonaws.com` 的憑證不符合任何主體別名。

### 常見原因
<a name="snapstart-dns-caching-cause"></a>

Lambda 函數已快取 DNS 回應。如果您透過 SnapStart 使用其他 DNS 快取，則當函數從快照恢復，可能會發生連線逾時的情況。

### Resolution
<a name="snapstart-dns-caching-resolution"></a>

為防止 Java 11 執行時期出現 `UnknownHostException` 失敗，建議將 `networkaddress.cache.negative.ttl` 設定為 0。在 Java 17 和更新版本的執行時期中，則不需要此步驟。您可以使用 `AWS_LAMBDA_JAVA_NETWORKADDRESS_CACHE_NEGATIVE_TTL=0` 環境變數為 Lambda 函數設定此屬性。

## 快照建立失敗
<a name="snapstart-creation-failure"></a>

**Error：** AWS Lambda 無法叫用您的 SnapStart 函數。如果此錯誤持續存在，請檢查函數的 CloudWatch 日誌，看看是否存在初始化錯誤。

### Resolution
<a name="snapstart-creation-failure-resolution"></a>

檢閱函數的 Amazon CloudWatch 日誌，了解檢查點前的[執行時期勾點](snapstart-runtime-hooks.md)逾時。您也可以嘗試發布新的函數版本，這麼做有時可以解決問題。

## 快照建立延遲
<a name="snapstart-creation-latency"></a>

**問題：**發布新的函數版本時，函數會長時間處於`Pending`[狀態](snapstart-activate.md#snapstart-function-states)。

### 常見原因
<a name="snapstart-creation-latency-cause"></a>

Lambda 建立快照時，初始化程式碼最多可能會執行 15 分鐘。時間限制為 130 秒或[設定的函數逾時](configuration-timeout.md) (最長 900 秒)，以較長者為準。

如果函數[已連接至 VPC](configuration-vpc.md#configuration-vpc-attaching)，Lambda 可能還需要在函數的狀態轉變成`Active`之前建立網路介面。如果您嘗試在函數處於`Pending`狀態時調用函數版本，則可能會遇到 409 `ResourceConflictException` 錯誤。如果使用 Amazon API Gateway 端點調用函數，則可能會在 API Gateway 中遇到 500 錯誤。

### Resolution
<a name="snapstart-creation-latency-resolution"></a>

請至少等待 15 分鐘，讓函數版本完成初始化，然後再調用它。