How do I reduce initialization and invocation duration latency for my Java Lambda function?
Last updated: 2021-07-07
My Java AWS Lambda function isn’t performing optimally. Why is this happening, and how do I reduce my Java function’s initialization and duration latency?
There are two main factors that can contribute to high latency in a Java Lambda function:
Java virtual machine (JVM) lazy class loading
To reduce memory usage, the JVM delays initializing a Java class library until the library is first called in an application. This delay can cause a high number of input-output (I/O) operations, which results in higher duration latencies for first invocations in a Lambda execution environment.
The Java Reflection API
The Java Reflection API allows Java code to discover information about other classes, interfaces, fields, and methods, and then operate on their underlying values. Because reflection involves types that are dynamically resolved, certain JVM optimizations can’t be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts.
To optimize your Java Lambda function’s performance, you can implement one or more of the best practices outlined in this article.
Note: To see a specific case study, watch AWS re:Invent 2019: Best practices for AWS Lambda and Java.
Configure provisioned concurrency for your Lambda function
Provisioned concurrency initializes a requested number of execution environments so that they are prepared to respond immediately to your function's invocations. To set up provisioned concurrency for your function, follow the instructions in Configuring provisioned concurrency.
For more information, see Managing concurrency for a Lambda function.
Note: Configuring provisioned concurrency incurs charges to your AWS account. You can configure provisioned concurrency on a version of a function or on a Lambda function alias.
Initialize your function's static logic outside of the function handler
When you initialize a Lambda function, Lambda allocates a burst of host CPU capacity for up to 10 seconds. Because of this CPU burst, it’s a best practice to do the following outside of the function handler:
- Import libraries and dependencies
- Set up configuration
- Initialize connections to other services
This static initialization allows these resources to be initialized once per sandbox and then reused for all future invocations in the execution environment.
For more information, see Optimizing static initialization.
Make API calls to any lazily loaded libraries outside of the function handler
To avoid lazy loading of libraries during initialization, you can make dummy API calls to any lazily loaded libraries outside of the function handler. These dummy calls initialize the libraries and prewarm the SDK that you're using.
Note: Dummy calls to lazily loaded libraries can fail if Lambda doesn't have the information required for a successful API call. If the call fails, make sure that you catch the error.
Reduce reflective operations in your Lambda code
Reflective operations have slower performance than their non-reflective counterparts. Avoid reflective operations in sections of code that are called frequently.
Reduce the number of classes in your application
Reducing the size of your deployment package to its runtime necessities reduces the amount of time that it takes to invoke your function.
For more information, see Best practices for working with AWS Lambda functions.
Set your Lambda function’s configuration parameters in advance
Setting your function’s configuration parameters in advance reduces your function’s invocation and duration latency. If you don’t specify configuration variables in your code, it takes Lambda more time to discover the default variables for your function.
For more information, see the Function code section of Best practices for working with AWS Lambda functions.
Update to AWS Java SDK 2.0
For more information, see Tuning the AWS Java SDK 2.x to reduce startup time.
Note: The AWS Java SDK 2.0 includes the Apache HTTP client and Netty HTTP client by default, along with the Java HTTP URL Connection client. It’s a best practice to remove the Apache and Netty HTTP clients from your deployment package if they’re not required for your use case.