

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 缩短 SDK 的启动时间 AWS Lambda
<a name="lambda-optimize-starttime"></a>

的目标之一 AWS SDK for Java 2.x 是减少 AWS Lambda 函数的启动延迟。SDK 包含可缩短启动时间的更改，本主题末尾将对此进行讨论。

首先，本主题重点介绍为缩短冷启动时间可以进行的更改。这包括更改代码结构和服务客户端的配置。

## 使用 AWS 基于 CRT 的 HTTP 客户端
<a name="lambda-quick-url"></a>

对于使用 AWS Lambda，我们建议在同步场景中使用，[https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/http/crt/AwsCrtHttpClient.html)对于异步场景，我们建议使用。

本指南中的 [配置 AWS 基于 CRT 的 HTTP 客户](http-configuration-crt.md) 主题描述了使用 HTTP 客户端的好处、如何添加依赖项以及如何按服务客户端配置其使用。

## 移除未使用的 HTTP 客户端依赖项
<a name="lambda-quick-remove-deps"></a>

除了明确使用 AWS 基于 CRT 的客户端外，您还可以移除 SDK 默认引入的其他 HTTP 客户端。当需要加载的库较少时，Lambda 启动时间会缩短，因此您应该移除 JVM 需要加载的所有未使用的构件。

以下 Maven `pom.xml` 文件片段展示了排除基于 Apache 的 HTTP 客户端和基于 Netty 的 HTTP 客户端的情况。（当您使用 AWS 基于 CRT 的客户端时，不需要这些客户端。） 此示例将 HTTP 客户端项目排除在 S3 客户端依赖项之外，并添加了该`aws-crt-client`对象以允许访问 AWS 基于 CRT 的 HTTP 客户端。

```
<project>
    <properties>
        <aws.java.sdk.version>2.27.21</aws.java.sdk.version>
    <properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>${aws.java.sdk.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>aws-crt-client</artifactId>
        </dependency>
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>netty-nio-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>software.amazon.awssdk</groupId>
                    <artifactId>apache-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</project>
```

**注意**  
将 `<exclusions>` 元素添加到 `pom.xml` 文件中的所有服务客户端依赖项中。

## 配置服务客户端以进行快捷查找
<a name="lambda-quick-clients"></a>

**指定区域**  
创建服务客户端时，在服务客户端生成器上调用 `region` 方法。这简化了 SDK 的默认[区域查找过程，该过程](region-selection.md#default-region-provider-chain)会在多个位置检查 AWS 区域 信息。  
要使 Lambda 代码独立于区域，请在 `region` 方法中使用以下代码。此代码访问 Lambda 容器设置的 `AWS_REGION` 环境变量。  

```
Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))
```

**使用 `EnvironmentVariableCredentialProvider`**  
与区域信息的默认查找行为非常相似，SDK 会在多个位置查找凭证。通过在生成服务客户端时指定 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/EnvironmentVariableCredentialsProvider.html)，可以节省 SDK 凭证查找过程的时间。  
使用此凭证提供程序可以将代码用于 Lambda 函数，但可能无法在 Amazon EC2 或其他系统上运行。  
如果您打算在某个时候使用 [Lambd SnapStart a for Java](#lambda-quick-snapstart)，则应依靠默认的凭证提供程序链来查找证书。如果您指定`EnvironmentVariableCredentialsProvider`，则初始凭证查找起作用，但是激活后 SnapStart ，[Java 运行时会设置容器凭据环境变量](https://docs.aws.amazon.com/lambda/latest/dg/snapstart-activate.html#snapstart-credentials)。激活后，`EnvironmentVariableCredentialsProvider` 使用的环境变量（访问密钥环境变量）对 Java SDK 不可用。

以下代码段显示了为在 Lambda 环境中使用而经过适当配置的 S3 服务客户端。

```
S3Client s3Client = S3Client.builder()
    .region(Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable())))
    .credentialsProvider(EnvironmentVariableCredentialsProvider.create())
    .httpClient(AwsCrtHttpClient.builder().build())
    .build();
```

## 在 Lambda 函数处理程序之外初始化 SDK 客户端
<a name="lambda-quick-initialize"></a>

我们建议在 Lambda 处理程序方法之外初始化 SDK 客户端。这样，如果重复使用执行上下文，则可以跳过服务客户端的初始化。通过重复使用客户端实例及其连接，处理程序方法的后续调用可更快进行。

在以下示例中，使用静态工厂方法在构造函数中初始化 `S3Client` 实例。如果重复使用由 Lambda 环境管理的容器，则会重复使用初始化的 `S3Client` 实例。

```
public class App implements RequestHandler<Object, Object> {
    private final S3Client s3Client;

    public App() {
        s3Client = DependencyFactory.s3Client();
    }

    @Override
    public Object handle Request(final Object input, final Context context) {
         ListBucketResponse response = s3Client.listBuckets();
         // Process the response.
    }
}
```

## 尽量减少依赖关系注入
<a name="lambda-quick-di"></a>

依赖关系注入 (DI) 框架可能需要更多时间才能完成设置过程。它们可能还需要额外的依赖项，这需要一段时间才能加载。

如果需要 DI 框架，建议使用诸如 [Dagger](https://dagger.dev/dev-guide/) 之类的轻量级 DI 框架。

## 使用 Maven Archetype 瞄准 AWS Lambda
<a name="lambda-quick-maven"></a>

 AWS Java SDK 团队开发了一个 [Maven Archetype](https://github.com/aws/aws-sdk-java-v2/tree/master/archetypes/archetype-lambda) 模板，可以在最短的启动时间内启动 Lambda 项目。您可以从该原型构建 Maven 项目，并知道依赖项的配置非常适合 Lambda 环境。

要了解有关原型的更多信息并完成示例部署，请参阅此[博客文章](https://aws.amazon.com/blogs/developer/bootstrapping-a-java-lambda-application-with-minimal-aws-java-sdk-startup-time-using-maven/)。

## 考虑一下适用于 Java 的 Lambda SnapStart
<a name="lambda-quick-snapstart"></a>

如果您的运行时要求兼容，则 AWS 提供适用[ SnapStart 于 Java 的 Lambda](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html)。Lambda SnapStart 是一种基于基础设施的解决方案，可提高 Java 函数的启动性能。当您发布新版本的函数时，Lambda 会对其进行 SnapStart 初始化，并拍摄内存和磁盘状态的不可变加密快照。 SnapStart 然后缓存快照以供重复使用。

## 影响启动时间的 2.x 版更改
<a name="example-client-configuration"></a>

除了您对代码所做的更改外，适用于 Java 的 SDK 2.x 版本还包括三项可缩短启动时间的主要更改：
+ 使用 [jackson-jr](https://github.com/FasterXML/jackson-jr)，它是一个序列化库，可以改进初始化时间
+ 对日期和时间对象使用 [java.time](https://docs.oracle.com/javase/8/docs/api/index.html?java/time.html) 库，此为 JDK 的一部分。
+ 对记录 facade 使用 [Slf4j](https://www.slf4j.org/)。

## 其他资源
<a name="lambda-quick-resources"></a>

 AWS Lambda 开发者指南中有一[节介绍开发非 Java 特定的 Lambda 函数的最佳实践](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html)。

有关使用 Java 构建云原生应用程序的示例 AWS Lambda，请参阅此[研讨会内容](https://github.com/aws-samples/aws-lambda-java-workshop)。该研讨会讨论了性能优化和其他最佳实践。

您可以考虑使用提前编译的静态映像来减少启动延迟。例如，您可以使用适用于 Java 的 SDK 2.x 和 Maven 来[构建 GraalVM 原生映像](setup-project-graalvm.md)。