An overview of the

The SpringBoot framework needs no introduction, and Java programmers know it. Fewer people may be relatively familiar with Quarkus. The slogan on the front page of Quarkus is “Supersonic Subatomic Java.” It is a Kubernetes Native Java technology stack tailored for OpenJDK HotSpot and GraalVM, based on best-in-class Java libraries and standards. The arrival of Quarkus brings an innovative platform for developing Linux containers and Kubernetes native Java microservices.

In this article, we’ll do a simple comparison between the two Java frameworks, Spring Boot and Quarkus. We can better understand the similarities and differences between them, as well as some particularities. We also perform some tests to measure their performance. Finally, we’ll cover how a developer can transition from Spring to Quarkus.

SpringBoot

Spring Boot is a Java-based framework focused on enterprise applications. It makes it easy to use all Spring projects and integrates many out-of-the-box features to help developers become more productive.

Spring Boot reduces the amount of configuration and boilerplate code. In addition, because its conventions are superior to configuration methods, it automatically registers default configurations based on dependencies, greatly shortening the development cycle of Java applications.

Quarkus

Quarkus is another framework that takes a similar approach to Spring Boot as described above, but with the added benefit of delivering smaller artifacts (Supersonic, Subatomic) with faster startup time, better resource utilization, and efficiency.

It is optimized for cloud, serverless, and containerized environments. Although the focus is slightly different, Quarkus also integrates well with the most popular Java frameworks.

To compare

As mentioned above, both frameworks have good integration with other projects and frameworks. However, their internal implementation and architecture are different. For example, Spring Boot provides two types of Web functionality: blocking (Servlets) and non-blocking (WebFlux).

Quarkus, on the other hand, also provides both methods, but unlike Spring Boot, it allows us to use both blocking and non-blocking methods. In addition, Quarkus has embedded a reactive programming approach into its architecture.

To get more accurate data in our comparison, we will use two fully responsive applications implemented using Spring WebFlux and Quarkus responsive features.

In addition, one of the most important features in the Quarkus project is the ability to create Native Images (executable binaries based on a particular platform). Therefore, we will also include two native images in the comparison, but Spring’s native image support is still experimental. And we need GraalVM.

The test application

Our application will implement three apis: one that allows the user to create a zip code, another that looks up information for a specific zip code, and finally a zip code query by city. These apis are implemented using the previously mentioned Spring Boot and Quarkus’ reactive approach, and the database is PostgreSQL.

Our goal is to create a sample program that is slightly more complex than the HelloWorld program. Of course, the implementation of things like database drivers and serialization frameworks can affect our comparison results. However, most applications will probably need to handle these things.

Therefore, the purpose of the comparison is not to prove which framework is better or more efficient, but to analyze a case study of these particular implementations.

The test plan

To test both implementations, we will use JMeter to perform the tests and analyze their test reports. In addition, we will use VisualVM to monitor the application’s resource utilization during test execution.

The test will run for 5 minutes, calling all apis, starting with the warm-up period and then increasing the number of concurrent users until it reaches 1,500. We will start populating the database in the first few seconds and then start the query as follows:

All tests are performed on machines of the following specifications:

The end result may be less than ideal due to the lack of isolation from other background processes, but as mentioned earlier, we have no intention of conducting an extensive and detailed analysis of the performance of the two frameworks.

The results of the survey

Both projects are great experiences for developers, but it’s worth noting that Spring Boot has better documentation and more information is available online. Quarkus is improving in this area, but it’s still a bit behind.

In terms of indicators, we have the following results:

From this experiment, we observed that Quarkus was almost twice as fast as Spring Boot in terms of startup time for both the JVM and native versions. Build times are also much faster. In the case of native mirroring, build time: 9 minutes (Quarkus) versus 13 minutes (Spring Boot) and JVM build time: 20 seconds (Quarkus) versus 39 seconds (Spring Boot).

The same is true for Artifact sizes, and Quarkus has taken the lead again by generating smaller artifacts. Native images: 75MB (Quarkus) versus 109MB (Spring Boot), and JVM versions: 4KB (Quarkus) versus 26MB (Spring Boot).

On other indicators, the conclusions are less obvious. So we need to take a closer look.

CPU

We see JVM versions consume more CPU at the beginning of the warm-up phase. After that, CPU usage leveled off, with all versions consuming relatively equally.

Here are the CPU consumption of Quarkus in JVM and Native versions:

JVM version of Quarkus

Native version of Quarkus

memory

Memory is even more complicated. First, it is clear that the JVM versions of both frameworks reserve more memory for the Heap. Still, Quarkus reserved less memory from the start, as did memory utilization during startup.

Then, looking at utilization during testing, we can observe that the Native version doesn’t seem to reclaim memory as efficiently or as frequently as the JVM version. This can be improved by tweaking some of the parameters, and in this comparison, we used the default parameters without making changes to GC, JVM options, or any other parameters.

Let’s take a look at the memory usage graph:

Spring Boot JVM write write write

Quarkus JVM write write write

Spring Boot native: ↑

Quarkus native write write write

Quarkus did consume less memory resources during the test, despite higher spikes.

The response time

Finally, Spring Boot seems to have a slight advantage in terms of response time and number of threads used at peak times. It can handle the same load with fewer threads, while also having better response times.

The Spring Boot Native version performs better in this situation. But let’s look at the response time distribution for each version:

Spring Boot JVM write write write

Despite the more outliers, the Spring Boot JVM version made the best progress over time, most likely due to JIT compiler optimization.

Quarkus JVM write write write

Spring Boot native: ↑

Quarkus native write write write

Quarkus has shown great strength in low resource utilization. However, at least in this experiment, Spring Boot was on par with Quarkus in terms of throughput and responsiveness.

Both frameworks can handle all requests without any errors. Not only that, their performance is very similar, there is not much difference.

In a nutshell

All things considered, both frameworks are good choices when implementing Java applications.

Native applications are fast and low in resource consumption, making them an excellent choice for serverless, short-living applications and resource-sensitive environments.

JVM applications, on the other hand, seem to have more overhead, but have excellent stability and high throughput over time, making them ideal for robust, long-lived applications.

The code for the test programs and the scripts used to test them are available on GitHub.

Switch from Spring to Quarkus

With the rise of K8s, the Quarkus framework, which supports native applications well, is gaining attention and many developers are considering switching from Spring to Quarkus. However, developers often have to shelve their existing knowledge when starting to evaluate a new framework. Fortunately, Quarkus is different, as it was founded by a group of engineers with deep expertise in Java technology. This includes Spring API compatibility, and Quarkus was founded by the same engineers who support Spring Boot on Red Hat Runtime.

I’m a Spring developer. Why Quarkus?

It is becoming increasingly clear that containerization, and Kubernetes in particular, is forcing a reevaluation of Java for developing cloud-native applications. Kubernetes is a highly dynamic shared infrastructure. The infrastructure investment becomes more cost-effective as the number of applications hosted in the cluster increases and the ability to respond to changes in the application life cycle, such as redeployment and scaling up/down. The traditional Java cloud native runtime adds new layers on top of the existing stack without really rethinking the underlying layer. This leads to greater memory consumption and slower startup times, so much so that companies are now willing to give up their deep Java expertise to retrain talent and development tools for Go and Node.js in order to get more value out of the massive investment in the Kubernetes cluster.

Traditional cloud native Java stack: up

That’s the problem Quarkus addresses. Quarkus is optimized for memory usage and fast startup times. Quarkus applications running on the JVM can provide nearly twice as many application instances in the same amount of RAM as other cloud-native Java stacks, and the number of instances increases seven-fold when packaged as native binaries. This is more than simply compiling to native binaries using SubstrateVM (a feature of GraalVM). Quarkus optimizes the traditional “highly dynamic” framework for Kubernetes infrastructure, which reduces memory utilization and speeds up initial startup, resulting in a significant increase in runtime efficiency. These optimized and well-documented frameworks are called extensions and consist of best-in-class standard apis.

Runtime efficiency: ↑

Quarkus stack write write write

Why did we migrate from Spring Boot to Quarkus?

Take our company for example, our old system is based on Spring and Tomcat. This traditional framework gave us some headaches when we were maintaining and deploying, and we decided to migrate to Quarkus for the following reasons:

  • Memory and CPU consumption: For the operations being performed, the Spring and Tomcat frameworks are using too many resources beyond the primary purpose of the application.
  • Warm-up time: It may take 10-20 seconds for the Spring application to start up before the application can begin to warm up.
  • Useless code: As developers, we all hate boilerplate code.
  • Testing: Quarkus makes it easy to write unit and integration tests. Just type a @Quarkustest annotation there, and it will actually launch the entire application to run your tests.
  • Scale-out vs. scale-up: The smaller each application is (in terms of resources), the more we can add. Horizontal scalability wins out here.
  • Learning curve: Quarkus’ online documentation is easy to understand.

What existing knowledge can Spring developers bring to Quarkus?

Quarkus’s Spring API compatibility includes Spring DI, Spring Web, and Spring Data JPA. Other Spring apis, such as Spring Security and Spring Config, are also being planned. When run on the JVM, Quarkus applications can leverage almost any Java library. As long as you don’t use Java reflection, these Java libraries can be compiled native. For example, the Lombok library, popular with Spring developers, can be compiled natively. To be clear, Spring API compatibility in Quarkus is not intended to re-host existing Spring applications as a complete Spring platform. The goal is to make developing new applications based on Quarkus a natural starter experience. Combined with pre-optimized extensions, Quarkus offers a wealth of functionality for microservice development. Many developers have successfully migrated Spring applications to Quarkus.

The Spring framework is highly dynamic by nature. To address this issue, Quarkus’s Spring Compatibility extension maps the Spring API to apis in existing extensions that have been optimized for fast startup, reduced memory utilization, and native compilation, such as RestEasy and CDI. In addition, Quarkus’s Spring compatibility extension does not use the Spring application context. For these reasons, trying to use additional Spring libraries may not work.

Quarkus Spring Web Example

import java.util.List;
import java.util.Optional;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/person")
public class PersonController {
    @GetMapping(path = "/greet/{id}", produces = "text/plain")
    public String greetPerson(@PathVariable(name = "id") long id) {
        String name="";
        // ...
        return name;
    }

    @GetMapping(produces = "application/json")
    public Iterable<Person> findAll(a) {
        return personRepository.findAll();
    }
Copy the code

Quarkus Spring Repository Example

package org.acme.springmp;

import java.util.List;
import org.springframework.data.repository.CrudRepository;

public interface PersonRepository extends CrudRepository<Person.Long> {
    List<Person> findByAge(int age);
}
Copy the code

Quarkus Spring Service + MicroProfile Fault Tolerance Example

import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Timeout;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service                                            // Spring
public class PersonService {

    @Autowired                                      // Spring
    @RestClient                                     // MicroProfile
    SalutationMicroProfileRestClient salutationRestClient;

    @Value("${fallbackSalutation}")                 // Spring
    String fallbackSalutation;

    @CircuitBreaker(delay=5000, failureRatio=.5)    // MicroProfile
    @Fallback(fallbackMethod = "salutationFallback")// MicroProfile
    public String getSalutation(a) {
        return salutationRestClient.getSalutation();
    }
Copy the code

Are there additional benefits for Spring developers?

In addition to improving memory utilization and startup time, Quarkus offers Spring developers the following benefits:

  • Function as a Service (FaaS). When compiled into native binaries, Quarkus applications can start in 0.0015 seconds, allowing you to combine existing Spring and Java API knowledge with FaaS functionality. (Azure, AWS Lambda)

  • Real-time coding. Start with the “Hello World” sample application and turn it into a complex microservice without restarting the application. Simply save and reload the browser to see the changes along the way. Quarkus real-time coding is “out of the box”, IDE independent.

  • Support for reactive and imperative models. Quarkus has a reactive core that supports traditional imperative models, reactive models, or both in the same application.

  • Early detection of dependency injection errors. Quarkus catches dependency injection errors at compile time rather than at run time.

  • A combination of the best frameworks and standards. Quarkus supports Spring API compatibility, Eclipse vert. x, MicroProfile (JAX-RS, CDI, etc.), reactive flow and messaging in the same application. See @Autowire MicroProfile into Spring Boot to use both Spring and MicroProfile apis in one project.

How should Spring developers start using Quarkus?

Recommended steps include:

  • See the getting Started guide for a general introduction to Quarkus.

  • See the guide to Spring DI, Spring Web, and Spring Data JPA.

  • Create a new application using code.quarkus. IO.

  • Watch Kubernetes Native Spring Apps in the Quarkus Devoxx demo

Refer to the link

www.baeldung.com/spring-boot…

Quarkus. IO/blog/quarku…

www.logicmonitor.com/blog/quarku…