Spring Boot vs Quarkus – Spring Boot vs Quarkus

最后修改: 2021年 10月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll make a simple comparison between two well-known Java frameworks, Spring Boot and Quarkus. At the end of it, we’ll better understand their differences and similarities and some particularities.

在这篇文章中,我们将对两个著名的Java框架Spring Boot和Quarkus进行简单比较。最后,我们将更好地了解它们的异同和一些特殊性。

Also, we’ll perform some tests to measure their performance and observe their behaviour.

此外,我们将进行一些测试,以衡量其性能并观察其行为。

2. Spring Boot

2.Spring启动

Spring Boot is a Java-based framework focusing on enterprise applications. It connects all Spring projects and helps to accelerate developers’ productivity by offering many production-ready integrations.

Spring Boot是一个基于Java的框架,专注于企业应用。它连接了所有的Spring项目,并且通过提供许多生产就绪的集成,帮助加快开发人员的生产力

By doing this, it reduces the amount of configuration and boilerplate. Furthermore, thanks to its convention over configuration approach, which automatically registers default configurations based on the dependencies available at the classpath in the runtime, Spring Boot considerably reduces the time-to-market for many Java applications.

通过这样做,它减少了配置和模板的数量。此外,由于其约定俗成的配置方法,即根据运行时classpath上的依赖关系自动注册默认配置,Spring Boot大大减少了许多Java应用程序的上市时间。

3. Quarkus

3.夸库斯

Quarkus is another framework with a similar approach as the Spring mentioned above Boot, but with an additional promise of delivering smaller artifacts with fast boot time, better resource utilization, and efficiency.

Quarkus是另一个框架,其方法与上面提到的Spring Boot类似,但它还有一个承诺,即提供较小的工件,具有快速启动时间、更好的资源利用率和效率

It’s optimized for cloud, serverless, and containerized environments. But despite this slightly different focus, Quarkus also integrates well with the most popular Java frameworks.

它针对云、无服务器和容器化环境进行了优化。但是,尽管重点略有不同,Quarkus也能很好地与最流行的Java框架集成。

4. Comparison

4.比较

As mentioned above, both frameworks integrate well with other projects and frameworks. However, their internal implementations and architectures are different. For example, Spring Boot offers web capabilities in two flavors: blocking (Servlets) and non-blocking (WebFlux).

如上所述,这两个框架都能很好地与其他项目和框架整合。然而,它们的内部实现和架构是不同的。例如,Spring Boot提供两种风格的Web功能。阻塞式(Servlets)非阻塞式(WebFlux)

On the other hand, Quarkus also offers both approaches, but unlike Spring Boot, it allows us to use both blocking and non-blocking strategies simultaneously. Moreover, Quarkus has the reactive approach embedded in its architecture.

另一方面,Quarkus也提供了这两种方法,但与Spring Boot不同,它允许我们同时使用阻塞和非阻塞策略。此外,Quarkus将反应式方法嵌入其架构中

For that reason, we’ll use two entirely reactive applications implemented with Spring WebFlux and Quarkus reactive capabilities to have a more exact scenario in our comparison.

出于这个原因,我们将使用两个完全由Spring WebFlux和Quarkus反应性功能实现的反应性应用,以便在我们的比较中拥有一个更确切的场景

Also, one of the most significant features available in the Quarkus project is the ability to create native images (binary and platform-specific executables). So, we’ll also include both native images in the comparison, but in the case of Spring, native image support is still in the experimental phase. To do this, we need the GraalVM.

此外,Quarkus项目中最重要的功能之一是能够创建本地图像(二进制和特定平台的可执行文件)。因此,我们也将在比较中包括这两种本地图像,但就Spring而言,本地图像支持仍处于实验阶段。要做到这一点,我们需要GraalVM

4.1. Test Applications

4.1.测试应用

Our application will expose three APIs: one allowing the user to create a zip code, the other to find the information of a particular zip code, and lastly, querying zip codes by city. These APIs were implemented using both Spring Boot and Quarkus entirely using the reactive approach, as already mentioned, and using a MySQL database.

我们的应用程序将暴露三个API:一个允许用户创建一个邮政编码,另一个是查找特定邮政编码的信息,最后是按城市查询邮政编码。这些API完全使用Spring Boot和Quarkus实现,如前所述,使用反应式方法,并使用MySQL数据库。

The goal was to have a simple sample application but with a little more complexity than a HelloWorld app. Of course, this will affect our comparison as the implementation of things like database drivers and serialization frameworks will influence the result. However, most applications are likely to deal with those things as well.

我们的目标是要有一个简单的示例应用程序,但要比HelloWorld应用程序更复杂一些。当然,这将影响我们的比较,因为像数据库驱动和序列化框架的实现会影响结果。然而,大多数应用程序也可能要处理这些东西。

So, our comparison doesn’t aim to be the ultimate truth about which framework is better or more performant, but rather a case study that will analyze these particular implementations.

因此,我们的比较并不旨在成为哪个框架更好或更有性能的最终真理,而是一个案例研究,将分析这些特定的实现。

4.2. Test Planning

4.2.测试规划

To test both implementations, we’ll use Wrk to perform the test, and its metrics report to analyze our findings. Also, we’ll use VisualVM to monitor the applications’ resource utilization during the test execution.

为了测试这两种实现,我们将使用Wrk来执行测试,并使用其度量报告来分析我们的发现。另外,我们将使用VisualVM来监测测试执行期间应用程序的资源利用率。

The test will run for 7 minutes, where all APIs will be called, starting with a warmup period and after increasing the number of connections until reaching 100 of them. Wrk can generate a significant amount of load with this setup:

测试将运行7分钟,所有的API将被调用,从热身期开始,在增加连接数后,直到达到100个。通过这种设置,Wrk可以产生大量的负载。

All the tests were performed on a machine with the following specifications:

所有的测试都是在一台具有以下规格的机器上进行的。

Although not ideal because of the lack of isolation from other background processes, the test only aims to illustrate the proposed comparison. It’s not the intention to provide an extensive and detailed analysis of the performance of both frameworks, as already mentioned.

尽管由于缺乏与其他后台进程的隔离,该测试并不理想,但其目的只是为了说明拟议的比较。如前所述,我们并不打算对两个框架的性能进行广泛而详细的分析。

Another point worth mentioning is that depending on our machine specification, we may need to adjust the number of connections, threads, etc.

另一点值得一提的是,根据我们的机器规格,我们可能需要调整连接数、螺纹数等。

4.3. Knowing Our Tests

4.3.了解我们的测试

It’s essential to ensure we are testing the right thing, so to do that, we’ll use Docker containers to deploy our infra. This will allow us to control the resource constraints of both the application and database. The goal is to stress the application now the underlying system, our the database. For this example, just limiting the number of available CPUs is enough, but this may change depending on the resources available in our machines.

确保我们的测试是正确的是至关重要的,所以为了做到这一点,我们将使用Docker容器来部署我们的Infra。这将使我们能够控制应用程序和数据库的资源限制。我们的目标是给应用程序和底层系统,也就是我们的数据库施加压力。在这个例子中,仅仅限制可用的CPU数量就足够了,但这可能会根据我们机器中的可用资源而改变。

To restrict the sources available, we can use the Docker settings, cpulimit command, or any other tool we prefer. Moreover, we may use the docker stats and top commands to monitor the system’s resources. Last in regarding memory we will measure the heap usage and also the RSS and to that let’s use the ps (ps -o pid,rss,command -p <pid>) command.

为了限制可用的资源,我们可以使用Docker设置cpulimit/em>命令,或任何我们喜欢的其他工具。此外,我们可以使用docker statstop命令来监控系统的资源。最后,在内存方面,我们将测量堆的使用情况和RSS,为此我们使用psps -o pid,rss,command -p <pid>)命令。

5. Findings

5.研究结果

The developer experience was great for both projects, but it’s worth mentioning that Spring Boot has better documentation and more material than we can find online. Quarkus is improving in this area and has a vast set of features that helps increase productivity. However, considering documentation and stack overflow issues, it’s still behind.

这两个项目的开发者体验都很好,但值得一提的是,Spring Boot有更好的文档,比我们在网上能找到的材料更多。Quarkus在这方面正在改进,有大量的功能,有助于提高生产力。然而,考虑到文档和堆栈溢出问题,它仍然落后。

In terms of metrics, we have:

在衡量标准方面,我们有。

With this experiment, we could observe that Quarkus was faster than Spring Boot in terms of startup time both in JVM and native versions. Furthermore, Quarkus build time was also much quicker in the case of native images. The build took 91 seconds (Quarkus) vs 113 seconds (Spring Boot), and the JVM build took 5.24 seconds (Quarkus) vs 1.75 seconds (Spring Boot), so point for Spring in this one.

通过这个实验,我们可以观察到Quarkus在JVM和本地版本的启动时间方面都比Spring Boot快。此外,Quarkus的构建时间在本地图像的情况下也要快得多。构建时间为91秒(Quarkus),而Spring Boot为113秒;JVM构建时间为5.24秒(Quarkus),而Spring Boot为1.75秒,所以Spring在这一点上胜出。

Regarding artifact size, the runnable artifacts produced by Spring Boot and Quarkus were similar in terms of the JVM version, but in the case of native ones, Quarkus did a better job.

关于工件的大小,Spring Boot和Quarkus产生的可运行工件在JVM版本方面相似,但在本地工件方面,Quarkus做得更好。

However, regarding other metrics, the conclusions are not straightforward. So, let’s take a deeper look at some of them.

然而,关于其他指标,结论并不直截了当。因此,让我们更深入地看一下其中的一些指标。

5.1. CPU

5.1. CPU

If we focus on the CPU usage, we’ll see that the JVM versions consume more CPU at the beginning during the warmup phase. After that, the CPU usage stabilizes, and the consumption becomes relatively equal to all the versions.

如果我们关注CPU的使用情况,我们会发现JVM版本在开始的时候热身阶段消耗更多的CPU。之后,CPU的使用趋于稳定,所有版本的消耗都变得相对相等。

Here are the CPU consumptions for Quarkus in JVM and Native versions, in that order:

以下是Quarkus在JVM和Native版本中的CPU消耗量,依次为:。

(Spring JVM)

(Spring JVM)

(Quarkus JVM)

(Quarkus JVM)

(Spring Native)

(Spring的土著)

(Quarkus Native)

(Quarkus Native)

Quarkus did better in both cases. However, the difference was so small that a tie could also be considered. Another point worth mentioning is that in the graph, we see the consumption based on the number of CPUs available in the machine. Still, to ensure we were stressing the option and not other parts of the system, we have limited the number of cores available to the application to three.

夸库斯在这两种情况下都做得更好。然而,差距太小,也可以考虑打平。另一点值得一提的是,在图表中,我们看到的是基于机器中可用的CPU数量的消耗。不过,为了确保我们是在给选项而不是系统的其他部分施加压力,我们将应用程序可用的核心数量限制为三个。

5.2. Memory

5.2.记忆

Regarding memory, it’s even more complicated. First, the JVM versions of both frameworks reserve more memory for the heap, almost the same amount of memory. Regarding heap usage, the JVM versions consume more memory than the native ones, but looking at the pairs, Quarkus seems to consume slightly less than Spring in the JVM version. But, again, the difference is super tiny.

关于内存,情况就更复杂了。首先,两个框架的JVM版本都为堆保留了更多的内存,几乎相同的内存量。关于堆的使用,JVM版本比本地版本消耗更多的内存,但看一下这对组合,Quarkus似乎在JVM版本中比Spring消耗的内存略少。但是,同样的,这个差别也是超级小的。

(Spring Boot JVM)

(Spring Boot JVM)

(Quarkus JVM)

(Quarkus JVM)

Then, looking at the native images, things seem to have changed. The Spring Native version seems to collect memory more frequently and keeps a lower memory footprint.

然后,看了看原生图像,事情似乎发生了变化。Spring Native版本似乎更频繁地收集内存,并保持较低的内存占用率

(Spring Boot Native)

(Spring Boot Native)

(Quarkus Native)

(Quarkus Native)

Another important highlight is that Quarkus seems to overtake Spring in both versions when it comes to RSS memory measurement. We only added the RSS comparison at the startup time, but we can also use the same command during the tests.

另一个重要的亮点是,在RSS内存测量方面,Quarkus似乎在两个版本中都超过了Spring。我们只在启动时添加了RSS比较,但我们也可以在测试过程中使用相同的命令。

Nevertheless, in this comparison, we only used the default parameters. Therefore, no changes were made to GC, JVM options, or any other parameters. Different applications may need different settings, we should have this in mind when using them in a real-life environment.

尽管如此,在这次比较中,我们只使用了默认参数。因此,没有对GC、JVM选项或任何其他参数进行修改。不同的应用程序可能需要不同的设置,我们在实际环境中使用时应该牢记这一点。

5.3. Response Time

5.3.响应时间

Lastly, we’ll use a different approach regarding response times as many of the benchmark tools available suffer from a problem called Coordinated Omission. We’ll use hyperfoil, a tool designed to avoid this issue. During the test, many requests are created, but the idea is not to stress the application too much but rather just enough to measure its response time.

最后,我们将使用关于响应时间的不同方法,因为许多可用的基准工具都存在一个称为协调遗漏的问题。我们将使用hyperfoil,这是一个旨在避免这一问题的工具。在测试过程中,会创建许多请求,但我们的想法是不要给应用程序施加太多压力,而只是为了测量其响应时间。

Though, the test structure is pretty much similar to the previous one.

虽然,测试结构与之前的测试基本相似。

(Spring Boot JVM)

(Spring Boot JVM)

(Quarkus JVM)

(Quarkus JVM)

Throughput and response time are not the same thing although related, they measure different things. Quarkus JVM version had a good performance under pressure and also when it comes to moderate load. It seems to have higher throughput and a slightly lower response time.

吞吐量和响应时间虽然相关,但不是一回事,它们衡量的是不同的东西。Quarkus JVM版本在压力下有很好的性能,当涉及到适度负载时也是如此。它似乎有更高的吞吐量和稍低的响应时间。

(Spring Boot Native)

(Spring Boot Native)

(Quarkus Native)

(Quarkus Native)

Looking at the native versions, the numbers change again. Now, Spring seems to have a slightly lower response time and higher throughput overall. However, looking at all the numbers, we can see that the difference is too small to define any clear winner.

看一下本地版本,数字再次发生变化。现在,Spring的响应时间似乎略低,整体吞吐量也更高。然而,观察所有的数字,我们可以看到,差异太小,无法定义任何明显的赢家。

5.4. Connecting the Dots

5.4.连接点

All things considered, both frameworks proved to be great options for implementing Java applications.

综合考虑,这两个框架都被证明是实现Java应用的绝佳选择。

The native apps have shown to be fast and to have low resource consumption, being excellent choices for serverless, short-living applications and environments where low resource consumption is critical.

本机应用程序已显示出快速和低资源消耗,是无服务器、短寿命应用程序和低资源消耗至关重要的环境的绝佳选择。

On the other hand, the JVM apps seem to have more overhead but excellent stability and high throughput over time, ideal for robust, long-living applications.

另一方面,JVM应用程序似乎有更多的开销,但随着时间的推移,具有出色的稳定性和高吞吐量,是健壮、长寿的应用程序的理想选择。

Finally, regarding the performance, all the versions have robust performance when compared, at least for our example. The difference is so tiny that we can say they have similar performance. Of course, we can argue that the JVM versions handled the heavy load better in terms of throughput while consuming more resources, and on the other hand, the native versions consumed less. However, this difference may not even be relevant depending on the use case.

最后,关于性能,所有的版本在比较时都有强大的性能,至少对于我们的例子而言。差异是如此之小,以至于我们可以说它们的性能相似。当然,我们可以说JVM版本在吞吐量方面更好地处理了重负载,同时消耗了更多的资源,另一方面,本地版本消耗的资源更少。然而,根据使用情况,这种差异甚至可能不相关。

Last, I have to point out that in the Spring application, we had to switch the DB driver because one recommended by the documentation had an issue. In contrast, Quarkus worked out of the box without any problems.

最后,我必须指出,在Spring应用程序中,我们不得不更换DB驱动程序,因为文档中推荐的一个驱动程序出现了问题。相比之下,Quarkus开箱即用,没有任何问题。

6. Conclusion

6.结语

This article compares the Spring Boot and Quarkus frameworks and their different deployment modes, JVM and Native. We also looked at other metrics and aspects of those applications. As usual, the code of the test application and scripts used to test them are available over on GitHub.

本文比较了Spring Boot和Quarkus框架及其不同的部署模式,JVM和Native。我们还研究了这些应用程序的其他指标和方面。像往常一样,测试应用程序的代码和用于测试它们的脚本可在GitHub上获得