

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

# 使用 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/)。