Hello world app deployed as an AWS Lambda as a fat Java JAR and also as a GraalVM native image using the AWS CDK. Useful for comparing building/deploying native vs pure Java on Lambdas.
This demo was derived from:
- https://github.com/marksailes/graalvm-on-lambda (described in https://www.graalvmonlambda.com/, but slightly outdated)
- https://github.com/aws-samples/serverless-graalvm-demo
Companion presentation: https://kitomann.com/#/sessions/7/scale-up-with-graalvm-and-aws-lambdas. See the presentation for background information (i.e. why use GraalVM, Lambda overview, etc).
To build this project, you must have the following installed:
- Maven 3.6.3
- GraalVM 22.0.0.2 with native image tool
- AWS CDK CLI
- If you don't have your credentials configured, an easy way to do it is to install the AWS CLI and configure them through the
aws
command.
- If you don't have your credentials configured, an easy way to do it is to install the AWS CLI and configure them through the
- Docker Desktop
Building and deployment is a two-step process:
- Build the Java JAR
cd function
mvn clean package
NOTE: You don't need to build the native image here, because this needs to be done on the target OS (Amazon Linux). It will be handled by the deployment process.
- Deploy to AWS Lambda
TIP: Make sure Docker Desktop is running before deploying.
NOTE: Currently this project is set to build using an ARM Docker image and deploy to Lambda ARM architecture (which is cheaper). To change to x86, edit InfrastructureStack.java.
The follow command does the following:
- Deploy the Java JAR using the AWS Java 11 Runtime
- Build a native image in an Amazon Linux Docker container and deploy a ZIP using an Amazon Linux custom runtime
cd infra
cdk deploy
NOTE: If the deployment fails, use
cdk --debug deploy
to get some more info about the root cause.
After deployment is complete, each deployment outputs a URL you can use for testing:
Outputs:
GraalVmLambdaDemoStack.HelloWorldGraalApiUrl = https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-graal
GraalVmLambdaDemoStack.HelloWorldJvmApiUrl = https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-jvm
GraalVmLambdaDemoStack.HelloWorldJvmSnapStartApiUrl = https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-jvm-snapstert
And you can use curl
(or your browser) to test:
$ curl https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-jvm
Hello world!
$ curl https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-graal
Hello world!
$ curl https://bchs2cynrg.execute-api.us-east-1.amazonaws.com/hello-world-jvm-snapstert
Hello world!
If you log into the AWS Console, you'll be able to find the following artifacts:
- CloudFormation Stack: GraalVmLambdaDemoStack
- Lambda: GraalVmLambdaDemoStack-HelloWorldFunctionGraalVm
- Lambda: GraalVmLambdaDemoStack-HelloWorldFunctionJvm
- Lambda: GraalVmLambdaDemoStack-LogRetentiona
- API Gateway Route: GraalVmLambdaDemoApi
- Route: /hello-world-graal
- Route: /hello-world-jvm
To see how these are configured, look at InfrastructureStack.java.
NOTE: I've also added another function called
GraalVmLambdaDemoStack-HelloWorldFunctionJvmSnapstart
. Currently this is exactly the same asHelloWorldFunctionJvm
, because SnapStart doesn't appear to be supported yet in the Java CDK. You must manually enable it as described here: https://docs.aws.amazon.com/lambda/latest/dg/snapstart-activate.html#snapshot-console.
You can find performance info in the AWS Console; the easiest way is to view the Lambda function, Monitor -> Logs and expand the request:
In general, you can expect the native image to have a faster cold start time, a faster response time, and lower memory utilization.
Java Runtime Logs:
Native Image Custom Runtime Logs: