Spring Boot 3 application on AWS Lambda - Part 7 Measuring cold and warm starts with AWS Lambda Web Adapter
Vadym Kazulkin
Posted on June 10, 2024
Introduction
In the part 5 of the series we introduced AWS Lambda Web Adapter tool, and in the part 6 we explained how to develop Lambda function with AWS Lambda Web Adapter using Java 21 and Spring Boot 3.
In this article of the series, we'll measure the cold and warm start time including enabling SnapStart on the Lambda function but also applying various priming techniques like priming the DynamoDB invocation and priming the whole web request. We'll use Spring Boot 3.2 sample application for our measurements, and for all Lambda functions use JAVA_TOOL_OPTIONS: "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" and give them Lambda 1024 MB memory. Current Spring Boot version 3.3. should work out of the box by switching the version in the POM file.
Measuring cold starts and warm time with AWS Lambda Web Adapter and using Java 21 and Spring Boot 3
Enabling SnapStart on Lambda function is only a matter of configuration like :
SnapStart:
ApplyOn: PublishedVersions
applied in The Lambda Function Properties or Global Functions section of the SAM template, I'd like to dive deeper to how to use priming on top of it for our use case. I explained the ideas behind priming (in our case of DynamoDB request) in my article AWS Lambda SnapStart - Part 5 Measuring priming, end to end latency and deployment time
The code for priming of DynamoDB request can be found here.
This class Priming is additionally annotated with
@Configuration so it will be initialized as well before the initialization of bean, repositories and controllers is completed.
It implements import org.crac.Resource interface of the CraC project.
With this invocation
Core.getGlobalContext().register(this);
Priming class registers itself as CRaC resource. We additionally prime the DynamoDB invocation by implementing beforeCheckpoint method from the CRaC API.
@Override
public void beforeCheckpoint(org.crac.Context<? extends Resource> context) throws Exception {
productDao.getProduct("0");
}
which we'll be invoked during the deployment phase of the Lambda function and before Firecracker microVM snapshot is taken.
Web request invocation priming that we explored with AWS Serverless Java Container in the article Spring Boot 3 application on AWS Lambda - Part 4 Measuring cold and warm starts with AWS Serverless Java Container is not applicable to AWS Lambda Web Adapter as the latter doesn't offer the formal API for the request invocation as AWS Serverless Java Container does.
The results of the experiment below were based on reproducing more than 100 cold and approximately 100.000 warm starts with Lambda function with 1024 MB memory setting for the duration of 1 hour. For it I used the load test tool hey, but you can use whatever tool you want, like Serverless-artillery or Postman.
I ran all these experiments on our GetProductByIdWithSpringBoot32WithLambdaWebAdapter Lambda function with 3 different scenarios with compilation option "-XX:+TieredCompilation -XX:TieredStopAtLevel=1" (client compilation without profiling). For further explanation please read my article about this topic AWS SnapStart - Part 14 Measuring cold starts and deployment time with Java 21 using different compilation options
1) No SnapStart enabled
in template.yaml use the following configuration:
Globals:
Function:
Handler: run.sh
CodeUri: target/aws-spring-boot-3.2-lambda-web-adapter-1.0.0-SNAPSHOT.jar
Runtime: java21
....
#SnapStart:
#ApplyOn: PublishedVersions
2) SnapStart enabled but no priming applied
in template.yaml use the following configuration:
Globals:
Function:
Handler: run.sh
CodeUri: target/aws-spring-boot-3.2-lambda-web-adapter-1.0.0-SNAPSHOT.jar
Runtime: java21
....
SnapStart:
ApplyOn: PublishedVersions
If we'd like to measure cold and warm starts, so the priming effect won't take place for the SnapStart enabled Lambda function we have to additionally remove @Configuration annotation from the Priming class or delete the entire Priming class.
3) SnapStart enabled with DynamoDB invocation priming
in template.yaml use the following configuration:
Globals:
Function:
Handler: run.sh
CodeUri: target/aws-spring-boot-3.2-lambda-web-adapter-1.0.0-SNAPSHOT.jar
Runtime: java21
....
SnapStart:
ApplyOn: PublishedVersions
and leave the Priming class described above as it is, so the priming effect takes place.
Abbreviation c is for the cold start and w is for the warm start.
Cold (c) and warm (w) start time in ms:
Scenario Number | c p50 | c p75 | c p90 | c p99 | c p99.9 | c max | w p50 | w p75 | w p90 | w p99 | w p99.9 | w max |
---|---|---|---|---|---|---|---|---|---|---|---|---|
No SnapStart enabled | 4777.94 | 4918.46 | 5068.17 | 5381.41 | 5392.18 | 5392.33 | 8.60 | 9.77 | 11.92 | 25.82 | 887.92 | 1061.54 |
SnapStart enabled but no priming applied | 1575.49 | 1649.61 | 2132.75 | 2264.57 | 2273.64 | 2274.45 | 8.26 | 9.38 | 11.09 | 23.46 | 1136.71 | 1161.12 |
SnapStart enabled with DynamoDB invocation priming | 674.35 | 709.61 | 974.14 | 1114.87 | 1195.66 | 1196.79 | 8.00 | 8.80 | 10.16 | 21.84 | 317.66 | 624.33 |
Conclusion
By enabling SnapStart on the Lambda function alone, it reduces the cold start time of the Lambda function significantly. By additionally using DynamoDB invocation priming we are be able to achieve cold starts only slightly higher than cold starts described in my article AWS SnapStart -Measuring cold and warm starts with Java 21 using different memory settings where we measured cold and warm starts for the pure Lambda function without the usage of any frameworks including 1024MB memory setting like in our scenario.
Comparing the cold and warm start times we measured with AWS Serverless Java Container in the article Measuring cold and warm starts with AWS Serverless Java Container we observe that AWS Lambda Web Adaptor offers much lower cold start times for all scenarios. Even priming DynamoDB invocation with AWS Lambda Web Adapter offers lower cold start times than the web request invocation priming for the Serverless Java Container. Warm start times are very similar for both approaches being very slightly lower for Serverless Java Container.
In the next part of the series, I'll introduce Spring Cloud Function project and concepts behind it as another alternative to develop and run Spring Boot applications on AWS Lambda.
Posted on June 10, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.