AWS Lambda Provisioned Concurrency - A Chance for Java and Spring Boot?

A couple of months ago I wrote about quick and small optimization for Java+Spring Boot AWS Lambda cold starts. You can find more details here. I also wrote that Spring Boot is not the best choice in serverless world and actually you’d better avoid it if you can.

Recently however things changed quite a bit. Amazon announced AWS Lambda Provisioned Concurrency and marketed it as “a solution for cold-starts problem”. How does it work with our Spring Boot application? Will it solve our cold start problems? Actually, which took me by total surprise, it may!

In my previous post I wrote that if your Spring Boot context starts up in longer than 10 seconds you should avoid initializing it in a static Java init section and lazily init before processing real Lambda request. This would allow you to save these wasted 10 seconds of init time during which it was not possible to init JVM runtime and then fully init Spring before processing the request.

Since then aws-serverless-java-container team introduced very clever trick: you can start Spring Boot initialization during Lambda init window, in asynchronous way, utilise about 10 seconds as much as possible with help of additional Thread, return main init thread gracefully tricking AWS into thinking that runtime was successfully initialized and then continuing background Thread initialization when processing real request. This allows to do some processing using init’s additional CPU power and then finish whatever was still not initialized just before the request. A couple of seconds gained.

Unfortunately it isn’t solving cold start problems. When requests come, they still face cold Lambdas which still can take more than 20 seconds to process the requests.

The solution is to use Lambda Warmers, for example Thundra. They periodically, for example every 5 minutes, call your Lambdas using N concurrent requests effectively keeping them warm and ready for real requests. This works and works well. There are some complications with warmers. You need to set them up, configure, then make your code aware of their existence and calls. You don’t have much flexibility in how to dynamically change their configuration.

AWS Lambda Provisioned Concurrency - A chance for Java and Spring Boot!

So, AWS Lambda Provisioned Concurrency. What does it do?

It consists of 2 major features that are very important to our case.

When you configure Provisioned Concurrency pool for specified Lambda version or alias, AWS:

1. Starts N instances of your Lambdas

This is very different from standard Lambda instance which waits for the first request and then sets up microVM, downloads your code, intializes runtime and only then starts processing the request. Provisioned Lambda is started and does all those steps at provisioning time. What is important to us is that our Java static sections and initialization are run. Moreover, AWS will automatically keep N Lambda instances ready all the time without any need to call your code. So you don’t have to make your code aware of any external or infrastructural mechanisms. You have N warm instances ready. All the time.

2. Allows init section to run for much more than 10 seconds

This is the most crucial here. I don’t know how long init window is for Provisioned Lambda. I run my big Spring Boot apps with some additional 40 seconds artificial sleep time, which sums up to 50 seconds, and it all happens in init window. This means that by using very simple code to init Spring Boot in synchronous manner Java’s static constructor allows us to have fully warm Lambdas, ready from the beginning, and ready all the time.

These 2 features are a massive step towards solving cold start problems for heavy apps like Java+Spring Boot. The best thing here is that, when our Java Lambda is warm it handles requests very efficiently and quickly winning with interpreted languages.

We don’t need additional warmers with their complications. We don’t need to complicate our code. Provisioned Concurrency allows us to have autoscaling-like windows during which we provision more instances. We can also think about handling real time events and react dynamically.

Summary

Of course there are drawbacks. One can easily argue that Provisioned Concurrency goes against Serverless spirit and principles and there isn’t really any way to defend it. After all we shouldn’t care about scaling or “instances”. We shouldn’t be concerned with analysing and thinking about external configuration related to - let’s not be afraid to say it - servers behind serverless. I’m pretty sure we will someday have this close-to-ideal serverless environment but it’s not today. For now, I’m very happy with what AWS did. To my surprise I’m now more likely to say that going with Java and Spring Boot on AWS Lambda kinda makes sense. If you have team of seasoned Spring developers and Provisioned Concurrency is acceptable to you then you can create very efficient and production ready solution.

Efficient Cloud That Suits Your Pocket

We have many years of experience with migrating, designing and optimizing Cloud systems. Let us prepare a solution that suits your needs.

Schedule a call with our expert