Reduce SDK startup time for AWS Lambda - AWS SDK for Java 2.x

Reduce SDK startup time for AWS Lambda

One of the goals of the AWS SDK for Java 2.x is to reduce the startup latency for AWS Lambda functions. The SDK contains changes that reduce startup time, which are discussed at the end of this topic.

First, this topic focuses on changes that you can make to reduce cold start times. These include making changes in your code structure and in the configuration of service clients.

Use an AWS CRT-based HTTP client

For working with AWS Lambda, we recommend the AwsCrtHttpClient for synchronous scenarios and the AwsCrtAsyncHttpClient for asynchronous scenarios.

The Configure AWS CRT-based HTTP clients topic in this guide describes the benefits of using the HTTP clients, how to add the dependency, and how configure their use by service clients.

Remove unused HTTP client dependencies

Along with the explicit use of an AWS CRT-based client, you can remove other HTTP clients that the SDK brings in by default. Lambda startup time is reduced when fewer libraries need to be loaded, so you should remove any unused artifacts that the JVM needs to load.

The following snippet of a Maven pom.xml file shows the exclusion of the Apache-based HTTP client and the Netty-based HTTP client. (These clients aren't needed when you use an AWS CRT-based client.) This example excludes the HTTP client artifacts from the S3 client dependency and adds the aws-crt-client artifact to allow access to the AWS CRT-based HTTP clients.

<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>
Note

Add the <exclusions> element to all service client dependencies in your pom.xml file.

Configure service clients to shortcut lookups

Specify a region

When you create a service client, call the region method on the service client builder. This shortcuts the SDK's default Region lookup process that checks several places for the AWS Region information.

To keep the Lambda code independent of the region, use the following code inside the region method. This code accesses the AWS_REGION environment variable set by the Lambda container.

Region.of(System.getenv(SdkSystemSetting.AWS_REGION.environmentVariable()))
Use the EnvironmentVariableCredentialProvider

Much like the default lookup behavior for the Region information, the SDK looks in several places for credentials. By specifying the EnvironmentVariableCredentialProvider when you build a service client, you save time in the SDK's lookup process for credentials.

Note

Using this credentials provider enables the code to be used in Lambda functions, but might not work on Amazon EC2 or other systems.

If you intend to use Lambda SnapStart for Java at some point, you should rely on the default credentials provider chain to lookup credentials. If you specify the EnvironmentVariableCredentialsProvider, the initial credentials lookup works, but when SnapStart is activated, the Java runtime sets container credentials environment variables. On activation, the environment variables used by the EnvironmentVariableCredentialsProvider—access key environment variables—are not available to the Java SDK.

The following code snippet shows an S3 service client appropriately configured for use in a Lambda environment.

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

Initialize the SDK client outside of the Lambda function handler

We recommend initializing an SDK client outside of the Lambda handler method. This way, if the execution context is reused, the initialization of the service client can be skipped. By reusing the client instance and its connections, subsequent invocations of the handler method occur more quickly.

In the following example, the S3Client instance is initialized in the constructor using a static factory method. If the container that is managed by the Lambda environment is reused, the initialized S3Client instance is reused.

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. } }

Minimize dependency injection

Dependency injection (DI) frameworks might take additional time to complete the setup process. They might also require additional dependencies, which take time to load.

If a DI framework is needed, we recommend using lightweight DI frameworks such as Dagger.

Use a Maven Archetype targeting AWS Lambda

The AWS Java SDK team has developed a Maven Archetype template to bootstrap a Lambda project with minimal startup time. You can build out a Maven project from the archetype and know that the dependencies are configured suitably for the Lambda environment.

To learn more about the archetype and work through an example deployment, see this blog post.

Consider Lambda SnapStart for Java

If your runtime requirements are compatible, AWS offers Lambda SnapStart for Java. Lambda SnapStart is an infrastructure-based solution that improves startup performance for Java functions. When you publish a new version of a function, Lambda SnapStart initializes it and takes an immutable, encrypted snapshot of the memory and disk state. SnapStart then caches the snapshot for reuse.

Version 2.x changes that affect startup time

In addition to changes that you make to your code, version 2.x of the SDK for Java includes three primary changes that reduce startup time:

  • Use of jackson-jr, which is a serialization library that improves initialization time

  • Use of the java.time libraries for date and time objects, which is part of the JDK

  • Use of Slf4j for a logging facade

Additional resources

The AWS Lambda Developer Guide contains a section on best practices for developing Lambda functions that is not Java specific.

For an example of building a cloud-native application in Java that uses AWS Lambda, see this workshop content. The workshop discussion performance optimization and other best practices.

You can consider using static images that are compiled ahead of time to reduce startup latency. For example, you can use the SDK for Java 2.x and Maven to build a GraalVM native image.