Spring Framework 5.0 introduced Spring Cloud Function to aid the implementation of business logic as a function and to enable Spring Boot features on different serverless cloud providers (AWS Lambda, Azure, Google Cloud Platform, Oracle Fn platform and Apache OpenWhisk). Its "functional" style of bean declarations helps in the fast startup. Now, the AWS Lambda SnapStart feature will turbocharge the startup of your Java application by up to 10x at no additional cost.
In this post, we'll learn more about AWS Lambda SnapStart and run one Spring Cloud Function (Github: SpringBoot2AwsLambda) on AWS Lambda's Java 11 (Corretto) runtime to verify the improvement for cold start requests.
Lifecycle of Lambda Execution Environment
There are mainly three phases in the lifecycle of Lambda execution environment.
Lambda maintains the execution environment for some time for the next invocation to reuse (warm start).
In general, Java based frameworks take extra time to bootstrap because following activities.
- Different Class-Loaders load classes, libraries, extensions etc. into Java Virtual Machine (JVM), then performs linking and initialization.
- Frameworks like Spring Framework heavily uses reflection for runtime dependency injection (DI), component scanning, auto configuration etc.
- Finally JIT (Just in time) compilation to covert bytecodes to native machine code at run time.
Because of that, Init phase (function's initialization code) is slower for Java/Spring/Spring Boot applications. And this results cold start.
My sample Spring Cloud Function (with bare minimum dependencies/libraries) is just one liner to return a greeting message . Still it took ≈4.8 seconds in initialization phase for cold start request.
package com.awsjunkie.demo;
import java.util.function.Function;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.awsjunkie.demo.model.User;
@SpringBootApplication
public class SpringBoot2AwsLambdaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBoot2AwsLambdaApplication.class, args);
}
// org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
@Bean
public Function<User, String> uppercase() {
return user -> {
return String.format("Hello %s!", user.getName());
};
}
}
org.springframework.cloud.function.adapter.aws.FunctionInvoker
provided by AWS adapter for Spring Cloud Function.What Lambda SnapStart deos?
When Lambda SnapStart is enabled, Init phase happens when a Lambda function version is published.
Lambda takes Firecracker microVM snapshot of the initialized execution environment, encrypts the same and cache it for future use. For a cold start request, instead of initializing the execution environment, Lambda simply restores the persisted snapshot. This technique significantly reduces the cold start duration.
What is Firecracker?
Firecracker is an open source virtualization technology that is purpose-built for creating and managing secure, multi-tenant container and function-based services that provide serverless operational models. Firecracker runs workloads in lightweight virtual machines, called microVMs, which combine the security and isolation properties provided by hardware virtualization technology with the speed and flexibility of containers. - https://github.com/firecracker-microvm/firecracker
To see the improvement (if any), I invoked the SnapStart enabled lambda function version.
Now, there is no Init duration. Init phase already happened when we published the lambda function. We'll see the Restoration duration for all cold start requests. So we realized 5610.83 / 1084.97 ≈ 5x improvement for cold start requests just by enabling SnapStart. For a heavier application, we'll see more improvement.
Without SnapStart:
==================
Init duration (4821.37 ms) + Duration (789.46 ms) = Total (5610.83 ms)
With SnapStart:
===============
Restore duration (356.80 ms) + Duration (728.17 ms) = Total (1084.97 ms)
Performance Boost:
==================
(5610.83 / 1084.97) = 5.17x
Billed Restore Duration is lesser than Restoration duration because AWS does not charge for restoring the snapshot.
Restore Duration
: The time it takes for Lambda to restore a snapshot, load the runtime (JVM), and run any afterRestore
runtime hooks.Billed Restore Duration
: The time it takes for Lambda to load the runtime (JVM) and run any afterRestore
hooks. You are not charged for the time it takes to restore a snapshot.How to enable Lambda SnapStart ?
SnapStart supports Java managed runtime Java 11 (Corretto) onwards. It can be enabled only for published lambda function versions and aliases pointing to a version.
You can activate and manage Lambda SnapStart in many ways (e.g. AWS console, AWS CLI, AWS SAM, AWS CDK, CloudFormation etc.). Let's see how we can enable it using the AWS console.
Whenever we deal with snapshot/restore of the memory and disk state of execution environment, we must consider few other aspects to avoid undesired outcome. Please refer all the Best practices for working with Lambda SnapStart.