This project uses Quarkus, the Supersonic Subatomic Java Framework. The objective is to study the Quarkus framework and weigh its pros and cons. I have used following dependencies:
- Spring-di - Spring dependency injection
- Spring-web - Spring web annotations
- Spring-boot properties
- Mongo-panache - Spring data for MongoDB
These were easy to use and not much different from regular Spring boot application. Also, I have following additional dependencies to evaluate their compatibility with Quarkus and it was seamless.
- commons-lang
- lombok
- mapstruct
Quarkus app can be started in two modes
- JVM mode
- Native image mode
A few of prerequisites are needed if you are trying to build the native image in the bare-metal machine
- For instance, in Windows, you need to install Visual studio's C++ Build Tools and
run
mvn clean package -Pnative
by using thevcvars64.bat
in theC:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build
. - GraalVM - graalvm-ce-java11-20.1.0
- After installing GraalVM and setting necessary env variable run
gu install native-image
to download and install native image executables for your operating system.
You can run your application in dev mode that enables live coding using:
mvn quarkus:dev
You can run your application in production mode
- The application can be packaged using:
mvn clean package
It produces the quarkus-app-1.0.0-SNAPSHOT-runner.jar
file in the /target
directory.
Be aware it’s not an uber-jar as the dependencies are copied into the target/lib
directory.
Spring boot v2.3.x in now using this type of packing, as this significantly reduce time required to build a docker image as it creates a cache layer for jars in lib folder.
The application is now runnable using java -jar target/quarkus-app-1.0.0-SNAPSHOT-runner.jar
.
You can create a native executable using:
mvn clean package -Pnative
Or, if you don't have GraalVM installed, you can run the native executable build in a container using:
mvn package -Pnative -Dquarkus.native.container-build=true
You can then execute your native executable with: ./target/quarkus-app-1.0.0-SNAPSHOT-runner
To free yourself from the above tedious process, I have create Dockerfile.jvm
and Dockerfile.native
to abstract the process for building the jar or native executables.
docker build -f <Dockerfile-path> -t <image-name> .
Usually building native image in bare metal takes from 5 to 10 minutes as the process is both memory hungry and CPU intensive. This makes even worse when you are trying to build in a docker image, so I recommend increasing the CPU and RAM for Windows Docker desktop using settings and increasing the docker process priority for other operating systems
As promised, Quarkus application was able to start in less than 100ms, in the native image and production mode making it perfect for a serverless application. And roughly within a second while using it dev mode.
In native image mode, you get roughly 150MB image size, in which executable size is about 50MB.
Native images exhibit very low memory footprint. Just 100MB of RAM is needed for the docker container. JVM mode is similar to the Spring boot application's memory requirement. Here, it required 512MB of RAM.
It was quite a disappointment with the native image mode, it exhibited poor performance when compared to JVM mode. Although, GraalVM was able to introduce ahead-of-time compilation, it is no match with JVM JIT compiler. Please refer the Quarkus_benchmark.xlsx spreadsheet for the benchmark results.
On the contrary, Quarkus application in the JVM mode was able to easily surpass the benchmark of the spring boot. In fact, it managed to give nearly twice the throughput as in similar spring boot application.
- Quarkus with GraalVM's native image managed to out perform JVM in memory consumption and start up time segment but their is a significant dip in the performance.
- Use native image mode for a short lived, serverless applications
- Use JVM mode for a long lived, JVM applications.