缩短 SDK 的启动时间 Amazon Lambda - Amazon SDK for Java 2.x
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

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

缩短 SDK 的启动时间 Amazon Lambda

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

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

使用 SDK 的 UrlConnectionHttpClient

对于同步 场景,适用于 Java 的 SDK 2.x 提供了 UrlConnectionHttpClient 类,该类基于 JDK 的 HTTP 客户端类。由于 UrlConnectionHttpClient 基于类路径中已有的类,因此无需加载额外的依赖项。

有关将 UrlConnectionHttpClient 添加到 Lambda 项目并配置其使用的信息,请参阅配置基于 URLConnection 的 HTTP 客户端

注意

与 SDK 的 ApacheHttpClient 相比,UrlConnectionHttpClient 存在一些功能限制。ApacheHttpClient 是 SDK 中的默认异步 HTTP 客户端。例如,UrlConnectionHttpClient 不支持 HTTP PATCH 方法。

少数 Amazon API 操作需要补丁请求。这些操作的名称通常以 Update* 开头。以下是几个示例。

如果你可能使用UrlConnectionHttpClient,请先参阅你正在使用 Amazon Web Service 的 API 参考。了解您需要的操作是否使用 PATCH 操作。

使用 SDK 的 AwsCrtAsyncHttpClient

AwsCrtAsyncHttpClient 是 SDK 中用于缩短 Lambda 启动时间的异步 对应项。

AwsCrtAsyncHttpClient 是一个异步非阻塞 HTTP 客户端。它建立在 Amazon 公共运行时的 Java 绑定之上,该绑定是用 C 编程语言编写的。 Amazon 通用运行时开发的目标之一是快速性能。

本指南中关于配置 HTTP 客户端的部分包含有关向 Lambda 项目添加 AwsCrtAsyncHttpClient 和配置其用途的信息。

移除未使用的 HTTP 客户端依赖项

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

以下 Maven pom.xml 文件片段展示了排除基于 Apache 的 HTTP 客户端和基于 Netty 的 HTTP 客户端的情况。(使用 UrlConnectionHttpClient 时不需要这些客户端。) 此示例从 S3 客户端依赖项中排除 HTTP 客户端构件,并添加了引入 UrlConnectionHttpClient 类的 url-connection-client 构件。

<project> <properties> <aws.java.sdk.version>2.17.290</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>url-connection-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>

如果您使用 AwsCrtAsyncHttpClient,请将对 url-connection-client 的依赖项替换为对 aws-crt-client 的依赖项。

注意

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

配置服务客户端以进行快捷查找

指定区域

创建服务客户端时,在服务客户端生成器上调用 region 方法。这简化了 SDK 的默认区域查找过程,该过程会在多个位置检查 Amazon Web Services 区域 信息。

要使 Lambda 代码独立于区域,请在 region 方法中使用以下代码。此代码访问 Lambda 容器设置的 AWS_REGION 环境变量。

Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))
使用 EnvironmentVariableCredentialProvider

与区域信息的默认查找行为非常相似,SDK 会在多个位置查找凭证。通过在生成服务客户端时指定 EnvironmentVariableCredentialProvider,可以节省 SDK 查找过程的时间。

注意

使用此凭证提供程序可以将代码用于 Lambda 函数,但可能无法在 Amazon EC2 或其他系统上运行。

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

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

在 Lambda 函数处理程序之外初始化 SDK 客户端

我们建议在 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. } }

尽量减少依赖关系注入

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

如果需要 DI 框架,建议使用诸如 Dagger 之类的轻量级 DI 框架。

使用 Maven Archetype 瞄准 Amazon Lambda

Amazon Java SDK 团队开发了一个 Maven Archetype 模板,可以在最短的启动时间内启动 Lambda 项目。您可以从该原型构建 Maven 项目,并知道依赖项的配置非常适合 Lambda 环境。

要了解有关原型的更多信息并完成示例部署,请参阅此博客文章

考虑一下适用于 Java 的 Lambda SnapStart

如果您的运行时要求兼容,则 Amazon 提供适用 SnapStart 于 Java 的 Lambda。Lambda SnapStart 是一种基于基础设施的解决方案,可提高 Java 函数的启动性能。当您发布新版本的函数时,Lambda 会对其进行 SnapStart 初始化,并拍摄内存和磁盘状态的不可变加密快照。 SnapStart 然后缓存快照以供重复使用。

影响启动时间的 2.x 版更改

除了您对代码所做的更改外,适用于 Java 的 SDK 2.x 版本还包括三项可缩短启动时间的主要更改:

  • 使用 jackson-jr,它是一个序列化库,可以改进初始化时间

  • 对日期和时间对象使用 java.time 库,此为 JDK 的一部分。

  • 对记录 facade 使用 Slf4j

其他 资源

Amazon Lambda 开发者指南中有一节介绍开发非 Java 特定的 Lambda 函数的最佳实践

有关使用 Java 构建云原生应用程序的示例 Amazon Lambda,请参阅此研讨会内容。该研讨会讨论了性能优化和其他最佳实践。

您可以考虑使用提前编译的静态映像来减少启动延迟。例如,您可以使用适用于 Java 的 SDK 2.x 和 Maven 来构建 GraalVM 原生映像