Cloud computing, container technology, or systems for orchestrating containers like Kubernetes weren’t even a concept when Java was created. It was built to maximize throughput (requests/s) at the expense of CPU and memory consumption, resulting in a slow startup time.
As the world is moving from monolith to micro-service and serverless architecture where we have multiple instances of a service running scalability issues like startup delays and memory overhead can be very disadvantageous. Let’s take a look at what happens at start-up time.
Java application startup – BTS
Java as we know is an interpreted language which means initially the byte code is interpreted and compile it using JIT compiler so that it’s really fast but the startup time suffers. Java’s reflection enables runtime inspection, manipulation, invocation, and even the creation of new classes, interfaces, constructors, and methods by the application. Additionally, it enables runtime method invocation for applications regardless of the chosen access specifier (public, private, or protected). Due to the fact that these inspections and invocations are carried out at runtime rather than at compile time, reflection adds to startup time and memory consumption. All the classes’ metadata is retained in the JVM for the application’s lifetime.
Quarkus to the rescue
Developed at Red hat, Quarkus is an open source stack to write Java applications, more specifically for cloud native, microservice or serverless architecture. In Quarkus, classes used only at application startup are invoked at build time and not loaded into the runtime JVM. It also avoids reflection as much as possible, instead favoring static class binding. These design principles reduce the size, and ultimately the memory footprint, of the application running on the JVM.
How Quarkus works?
To answer this question we need to understand what does a framework does.
- Parse a bunch of config files
- Scan class paths and classes for annotation, getters and metadata
- Build framework metamodel objects
- Prepare reflection and build proxies
- Start and openIO, threads etc
What Quarkus does is to move all the bullet points mentioned above except last one from runtime to build time and hence very fast to boot. Since Quarkus loads only the classes that are part of the execution flow the size of the build artifacts is very less sometimes half the size of what we are customised to see with other frameworks
Benefits of Quarks
- Supersonic: It is about the startup time, the ahead of time (AOT) compilation helps in reducing the class loading at startup time significantly. It optimizes code for the JVM as well as compiling to native code for improved performance. All underlying technologies are AOT-enabled, and Quarkus continually incorporates new AOT-enabled technologies, standards, and libraries.
- Subatmoic: It is about memory. Since Quarkus works only with the classes required for execution flow the memory footprints is almost half the size of Spring applications
- Developers joy: With inbuilt dev mode feature, developers need not to restart their server again and again to test a feature but with Quarkus just change the code and it will reflect in your test instantly.
- Unifying reactive and imperative: Developers can use both imperative and reactive APIs within the same classes. Quarkus ensures that the imperative APIs will block appropriately while the reactive APIs remain non-blocking.
In this article, we understood the problem that lead to the development of Java framework “Quarkus”. We have also looked at the benefits of the Quarkus over everyone favourite Spring boot.