Optimize your Spring Boot application for AWS Fargate
Fast startup times are key to quickly react to disruptions and demand peaks, and they can increase the resource efficiency. With AWS Fargate, you don’t need to take care of the underlying container hosts; however, some changes are often needed to shorten the time to bootstrap your container and the application.
This post describes optimization techniques to be applied to Java applications that run on Fargate. We specifically look at Java Spring Boot applications in this post, but these optimizations can also be applied to other types of containerized Java applications.
You can find the demonstration application code on GitHub that shows you the different implementations.
Our example application is a simple REST-based Create Read Update Delete (CRUD) service that implements basic customer management functionalities. All data is persisted in an Amazon DynamoDB table accessed using the AWS SDK for Java V2.
The REST-functionality is located in the class
CustomerController, which uses the Spring Boot
RestController-annotation. This class invokes the
CustomerService, which uses the Spring data repository implementation,
CustomerRepository. This repository implements the functionalities to access an Amazon DynamoDB table with the AWS SDK for Java V2. All user-related information is stored in a Plain Old Java Object (POJO) called Customer.
The following architecture diagram presents an overview of the solution.
For our tests, we created seven different versions of our application:
- Version 1, not optimized, running on x86_64
- Version 2, not optimized, running on ARM64
- Version 3, custom Java runtime environment (JRE) and additional optimizations running on x86_64
- Version 4, custom JRE and additional optimizations running on ARM64
- Version 5, Spring Native (GraalVM AoT compilation) running on X86_64 with Ubuntu 22 parent image
- Version 6, Spring Native (GraalVM AoT compilation) running on ARM64 with Ubuntu 22 parent image
- Version 7, Spring Native (GraalVM AoT compilation) running on X86_64 with distroless parent image
You will need the following to complete the steps in this post:
- Docker Desktop or an Amazon Elastic Compute Cloud (EC2) instance and Docker Buildx
- AWS Command Line Interface (CLI) version 2
- AWS Cloud Development Kit (CDK) version 2.19.0 or later
- Node.js version 17.8.0 or later
- NPM version 8.5.5 or later
- Amazon Elastic Container Registry (ECR) repository
Multi-arch container images
Multi-arch (or multi-architecture) refers to container images for different processor architectures built from the same code. There are multiple ways to create multi-arch images. In this post, we use a QEMU-emulation to quickly create the multi-arch images. If you plan to use multi-arch images for more than just for testing purposes, then please consider to build your images using a proper CI/CD pipeline. The first step is to install the
Docker Buildx-CLI plugin. This step isn’t necessary if you’ve installed Docker Desktop, which includes
buildx and emulators out of the box.
In the next step, we start with a new builder:
Now we start building a multi-arch image with the buildx-parameter. In the following command, you can see that we specify two different architectures:
arm64. A multi-arch manifest is generated and in addition pushed into an Amazon ECR registry. Note that in the measurement, each version is strictly separated and executed at the same time, so each directory is used to build and push images of the corresponding architecture.
In the task definition for Amazon Elastic Container Service (ECS) with Fargate, we specify the parameter cpuArchitecture (valid values are
ARM64) to run your task using the desired CPU architecture. We will go into this in more detail in a later section.
Setting up the infrastructure
In the previous steps, we compiled the application to a native image and built a container image that has been stored in an Amazon ECR repository. Now, we set up the basic infrastructure consisting of an Amazon Virtual Private Cloud (Amazon VPC), an Amazon ECS cluster with Fargate launch type, a DynamoDB table, and an Application Load Balancer (ALB).
Codifying your infrastructure allows you to treat your infrastructure just as code. In this post, we use the AWS CDK, an open-source software development framework, to model and provision cloud application resources using familiar programming languages. The code for the AWS CDK application can be found in the demonstration application’s code repository under
The following sections set up the infrastructure in the AWS Region eu-west-1 for the first version of our application: