Spring Boot vs Quarkus Performance
Introduction
One of my main concerns about the Spring ecosystem is the amount of resources that a simple Spring Boot microservice consumes. As I mentioned in my previous post, Event Sourcing & CQRS: Learning points, when you have a considerable amount of Spring Boot microservices running in the cloud your cloud provider bill could be very expensive.
A few months ago, a colleague introduce me to Quarkus. There are many reasons to use Quarkus, but I was particularly interested in memory consumption optimisation.
That is the reason why I created a simple project to test by myself how Quarkus compares to Spring in terms of memory consumption and response time.
Spring Boot Application
The Spring Boot application has been generated from https://start.spring.io/. It is a simple application that contains the following dependencies:
- Spring Boot version 2.3.3.RELEASE
- Spring Web
- Spring Data JPA
- Spring Actuator
- Lombok
- Java 11
Quarkus Application
The Quarkus application has been built using the Quarkus code generator https://code.quarkus.io/. It is an out of the box application that contains the following dependencies:
- Quarkus platform version 1.6.1.Final
- Quarkus Resteasy
- Quarkus Smallrye health
- Quarkus Hibernate Panache
- Java 11
One of the benefits of using Quarkus is that you can generate, out of the box, a native docker image using GraalVM. Therefore, I will be comparing Spring boot against both native and non-native images.
Infrastructure
This project uses Terraform for creating and deploying resources to AWS.
Both applications will be using exactly the same infrastructure:
- 1 Application Load Balancer (ALB)
- 1 AWS ECS cluster
- 2 tasks running in the cluster. Each task has memory = 512MiB and CPU = 256.
- A MySQL 8.0.17 engine managed by AWS RDS
For more information, please check the terraform folder which contains all the modules and resources used.
Rest Controller
The idea of this project was to build a simple API that implements create and read operations. Both applications have implemented the same endpoints:
- GET /products: Returns the last 20 products.
- GET /products/{id}: Returns one single product for a given Id.
- POST /products: Saves a new product.
Load tests
Load testing has been done with Gatling. Gatling is a great developer tool to load test web applications.
The load test tries to simulate a common use case. Each user will perform the following actions:
- Gets all the latest products.
- Save a new product.
- Retrieve the product saved on step 2.
The test ramps up 200 users during the first minute and then keeps constantly 200 users for 2 hours.
Response time results
Resources results
Conclusion
The above results show better response times by Quarkus, particularly the native version. I usually pay more attention to the 99th percentile and the mean and in both cases, Quarkus perform better than Spring Boot.
On the other hand, I have to admit that I was surprised by the amount of memory Quarkus used. I was expecting the native version to have a lower memory consumption that Spring but that was not the case, while the non-native version was just slightly better than the Spring one.
The Spring Boot memory consumption kept growing quite sharp at some points, while Quarkus applications were more stable. That’s why I still have an outstanding question unanswered: What would have happened if I had run the tests for more than 2 hours?
Source Code
As usual, all source code can be found over on GitHub.
1 Response
[…] my previous post, I compared the performance of a simple REST controlled done with Quarkus and Spring boot. A few months, after I published that post, Spring launched a new project called Spring Native. The […]