DEV Community

Cover image for Serverless applications on AWS with Lambda using Java 25, API Gateway and Aurora DSQL - Part 9 Using Container Image with SnapStart and priming approach
Vadym Kazulkin for AWS Heroes

Posted on Originally published at vkazulkin.com

Serverless applications on AWS with Lambda using Java 25, API Gateway and Aurora DSQL - Part 9 Using Container Image with SnapStart and priming approach

Introduction

In part 8 of the series, we learned how to convert the sample application to one using a container image as a deployment artifact on AWS Lambda and measured the performance of the Lambda functions. We observed that the Lambda cold start times are quite high.

In this part, we'll enable SnapStart on the Lambda functions using a container image. We'll also apply priming techniques and measure the performance of the Lambda functions for all scenarios.

You can find the final version of our sample applications, which we can deploy on AWS Lambda as a container image, in the following GitHub repositories:

Besides the previous part, please read the following articles in this series to grasp the general concepts:

The business logic required to implement the Lambda SnapStart priming approaches and the measurement design is the same. The changes that we need to make for each Lambda function in the SAM templates of both projects are the same as those we covered in part 8.

Measurements of cold and warm start times of our application with JDBC and Hikari connection pool using a Container Image

For the sake of completeness, we provide the measurements for the "No SnapStart enabled" approach from part 8.

Cold (c) and warm (w) start time with -XX:+TieredCompilation -XX:TieredStopAtLevel=1 compilation in ms:

Approach 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 1886 2047 2218 2568 2628 2629 4.90 5.24 5.63 8.00 131.40 380
SnapStart enabled but no priming applied, all 929 967 1021 1183 1275 1275 5.06 5.46 5.86 8.50 387 854
SnapStart enabled but no priming applied, last 70 918 953 1018 1180 1180 1180 5.08 5.46 5.86 8.50 387 854
SnapStart enabled and DSQL database request priming applied, all 587 624 998 1030 1133 1134 5.06 5.46 5.86 8.60 319 762
SnapStart enabled and DSQL database request priming applied, last 70 585 614 990 1024 1024 1024 5.04 5.41 5.82 8.57 318 762
SnapStart enabled and full priming applied, all 560 589 698 931 1092 1092 5.02 5.35 5.72 8.67 195 643
SnapStart enabled and full priming applied, last 70 558 579 641 921 921 921 4.98 5.33 5.72 8.57 194 422

Measurements of cold and warm start times of our application with Hibernate and Hikari connection pool using a Container Image

For the sake of completeness, we provide the measurements for the "No SnapStart enabled" approach from part 8.

Cold (c) and warm (w) start time with -XX:+TieredCompilation -XX:TieredStopAtLevel=1 compilation in ms:

Approach 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 3971 4150 4229 4660 4914 4914 5.46 5.86 6.30 8.20 203 398
SnapStart enabled but no priming applied, all 1091 1132 1287 1410 1417 1418 5.55 6.01 6.40 8.53 516 868
SnapStart enabled but no priming applied, last 70 1080 1099 1151 1236 1236 1236 5.61 6.05 6.50 8.60 513 744
SnapStart enabled and DSQL database request priming applied, all 938 982 1097 1230 1237 1238 5.59 6.00 6.45 8.46 332 678
SnapStart enabled and DSQL database request priming applied, last 70 931 969 1012 1202 1202 1202 5.61 6.00 6.43 8.43 316 646
SnapStart enabled and full priming applied, all 637 666 928 1119 1231 1231 5.61 6.03 6.48 8.77 185 590
SnapStart enabled and full priming applied, last 70 629 648 706 988 988 988 5.63 6.05 6.50 8.84 182 535

Conclusion

In this part, we enabled SnapStart on the Lambda functions using a container image. We also applied priming techniques and measured the performance of the Lambda functions for all scenarios. What we observe is that both cold and warm start times are very competitive when using the container image. Especially if we compare them to the measurements we did for the Lambda Java 25 managed Lambda runtime. See the results in the article SnapStart and full priming for comparison. I especially look for 90th-percentile measurements where the performance of the Lambda function with a container image is significantly better. What we also see is that the effect of the snapshot tiered cache is not so strong for the container images (see the last 70 measurements). With GraalVM Native Image, we have even higher cold and warm start times compared to container images. It also requires quite high effort to create and maintain the GraalVM Native images. For the container image, it is medium effort.

For the performance-sensitive Lambda functions, using the container image as the packaging format provides a very good solution. This is especially true when enabling Lambda SnapStart, which recently became available, and implementing priming. Please note that SnapStart charges apply to the container images, while SnapStart for supported Java managed versions remains free on AWS Lambda. So, gaining additional performance with SnapStart for container images comes at an additional cost. That's why choosing a managed Java version versus a container image becomes a cost-performance trade-off.

Please also watch out for another series where I use a NoSQL serverless Amazon DynamoDB database instead of Aurora DSQL to do the same Lambda performance measurements.

If you like my content, please follow me on GitHub and give my repositories a star!

Please also check out my website for more technical content and upcoming public speaking activities.

Top comments (0)