Topic navigation

Blog Articles

Migrating Java applications to Quarkus, Part 2: Before and after

This article is a continuation of Migrating Java applications to Quarkus: Lessons learned, and here, I’ll make a comparison of performance metrics for building and running a Java app before and after Quarkus. My goal here is to demonstrate how awesome Quarkus is and maybe help you decide to use Quarkus to build your cool microservices.

To make the comparison, I’ll use the same application that was used in the previous article using Thorntail and Quarkus binaries. The comparison will be made based on the following metrics:

Time to build the whole project

UberJar size

Time spent to start the application for the first time

Average of memory usage

Average of CPU usage

Loaded classes and active threads

The application will be tested in three different environments, which are:

Here we have a big difference, Thorntail produces an uber jar five times bigger than Quarkus.

The next comparison shows the time spent to start the app the first time; usually, it takes longer to compare it. The app will be stopped after all plugins are started, tested on my local dev environment and on RPI:

This, in my opinion, is one of the most important metrics, and one that helped me decide to try Quarkus. It shows an amazing 30 seconds faster than my previous version on my local environment and around 137 seconds faster on RPI. This app particularly takes a few seconds to start, because it has around 10 plugins that do some tasks during startup leading to delays. But, imagine that your microservice is composed with a few Rest endpoints; it could be started in less than 1 second.

For now, let’s see how the Java memory behaves. The graphics below show information collected for 10 minutes:

Quarkus:

Thorntail:

This comparison is very interesting, as we can see, Quarkus has the best numbers except for the threads. The difference is not too big, but the memory usage is a way larger than Thorntail, and the number of the loaded classes is a way bigger, less than the half. With that said, when targeting devices like RPI, Quarkus is a perfect fit because it consumes a very small portion of physical resources.

The next metrics were done using the container images created with Thorntail and Quarkus version running on Red Hat OpenShift:

Quarkus:

Thorntail:

On OpenShift, we can also see a considerable difference in memory usage, but notice that this value can be decreased by fine-tuning the JVM memory configurations. For this example, such fine-tuning was not done.

Conclusion

My experience with migrating an old application running on Thorntail to Quarkus was very good, and so far, I’ve had only great results with the metrics. In my opinion, migration to Quarkus is a go; of course, there are dozens of different scenarios that I didn’t cover, but I believe that, in most scenarios, the migration can be done and great results can be achieved.

The following table compares all the results I found during my tests:

Metric

Quarkus

Thorntail

build time

01:01 min

01:20 min

uber jar size

38M

201M

startup time (local dev env)

0m10.633s

0m38.926s

startup time (rpi)

0m21.309s

2m38.637s

Heap Memory

~45M-~125M

~240M-~790M

Threads

~43

~62

Loaded Classes

~12.575

~26.744

CPU Usage

~0.3

~0.6

I hope this article is helpful and encourages you perhaps to try Quarkus in your next project or when migrating an existing one. For the next article, I will share more interesting stuff, which I had to do to make the application run well with a native image. So, stay tuned for the next installment.