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
AwsCrtAsyncHttpClient
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 theAWS_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 theEnvironmentVariableCredentialsProvider
—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
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
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.