Spring Boot与Quarkus | Baeldung
Spring Boot与Quarkus | Baeldung
在本教程中,我们将专注于两个知名的Java框架Spring Boot和Quarkus之间的简单比较。到结束时,我们将更好地理解它们的相似之处和差异,以及一些特殊性。我们还将执行一些测试来衡量它们的性能并观察它们的行为。
Spring Boot是一个基于Java的框架,专注于企业应用程序。它连接了所有Spring项目,并通过提供许多生产就绪的集成来帮助加速开发人员的生产力。
通过这样做,它减少了配置和样板代码的数量。此外,得益于其约定优于配置的方法,在运行时根据类路径上可用的依赖项自动注册默认配置,Spring Boot大大减少了许多Java应用程序的上市时间。
3. Quarkus
Quarkus是另一个框架,与Spring Boot有类似的方法,但额外承诺提供更小的构件、更快的启动时间、更好的资源利用和效率。
它针对云、无服务器和容器化环境进行了优化。但尽管重点略有不同,Quarkus也与大多数流行的Java框架很好地集成。
4. 比较
如上所述,两个框架都与其他项目和框架很好地集成。然而,它们的内部实现和架构是不同的。例如,Spring Boot提供两种网络功能的风味:阻塞(Servlets)和非阻塞(WebFlux)。
Quarkus也提供这两种方法,但与Spring Boot不同,它允许我们同时使用阻塞和非阻塞策略。此外,Quarkus在其架构中嵌入了响应式方法。
出于这个原因,我们将使用两个完全响应式的应用程序,使用Spring WebFlux和Quarkus的响应式功能来实现,以便在我们的比较中有一个更精确的场景。
另外,两个项目中最重要的特性之一是能够创建原生映像(二进制和特定平台的可执行文件)。因此,我们也将包括比较中的两个原生映像。
需要注意的是,本项目使用了Spring Boot版本3.1.3。Spring原生映像可以配置为与以前的版本一起工作:原生映像支持处于试验阶段。然而,从版本3开始,Spring Boot有原生映像支持。为此,我们需要GraalVM。
4.1. 测试应用程序
我们的应用程序将公开三个API:一个允许用户创建邮政编码,一个查找特定邮政编码的信息,以及一个按城市查询邮政编码。这些API是使用Spring Boot和Quarkus完全使用响应式方法实现的,并使用MySQL数据库。
目标是拥有一个简单的示例应用程序,但比HelloWorld应用程序稍微复杂一些。当然,这将影响我们的比较,因为像数据库驱动程序和序列化框架这样的实现将影响结果。然而,大多数应用程序也可能处理这些事情。
因此,我们的比较并不旨在成为关于哪个框架更好的终极真理,而是成为一个案例研究,将分析这些特定实现。
4.2. 测试计划
为了测试这两种实现,我们将使用Wrk进行测试,并使用其指标报告来分析我们的发现。我们还将使用VisualVM在测试执行期间监控应用程序的资源利用。
测试将持续5分钟,将调用所有API,从热身期开始,然后增加连接数,直到达到20个。Wrk可以在这个设置下产生大量的负载:

所有测试都在具有以下规格的机器上执行:

尽管由于缺乏与其他后台进程的隔离而不理想,但测试的目的仅在于说明所提出的比较。正如已经提到的,我们并不打算提供对两个框架性能的广泛和详细分析。
另一个值得提及的点是,根据我们的机器规格,我们可能需要调整连接数、线程数等。
4.3. 了解我们的测试
确保我们正在测试正确的事情至关重要,因此我们将使用Docker容器来部署我们的基础设施。这将允许我们控制应用程序和数据库的资源限制。目标是给应用程序施加压力,而不是底层系统,我们的数据库。对于这个例子,仅仅限制可用CPU的数量就足够了,但这可能会根据我们机器上可用的资源而改变。
要限制可用资源,我们可以使用Docker设置、cpulimit_命令或我们喜欢的任何其他工具。此外,我们可以使用_docker stats_和_top_命令来监控系统资源。最后,关于内存,我们将测量堆使用情况以及RSS。为此,我们将使用_ps(ps -o pid,rss,command -p <pid>)命令。
5. 发现
两个项目的开发体验都很棒,但值得一提的是,Spring Boot有更好的文档和更多的在线资源。Quarkus在这方面正在改进,并拥有大量功能,有助于提高生产力。然而,在文档和Stack Overflow问题方面,它仍然落后。
在指标方面,我们有:
| 指标 | Spring Boot JVM | Quarkus JVM | Spring Boot Native | Quarkus Native |
|---|---|---|---|---|
| 启动时间(秒) | 5.395 | 4.075 | 0.082 | 0.142 |
| 构建构件时间(秒) | 1.759 | 5.243 | 113 | 91 |
| 构件大小(MB) | 30.0 | 31.8 | 94.7 | 80.5 |
| 加载的类 | 8861 | 8496 | 21615 | 16040 |
| CPU使用率最大(%) | 100 | 100 | 100 | 100 |
| CPU使用率平均(%) | 82 | 73 | 94 | 92 |
| 启动时堆大小(MB) | 1048.57 | 1056.96 | – | – |
| 启动时使用的堆大小(MB) | 193.31 | 157.066 | 84.574 | 60.41 |
| 使用的堆最大(MB) | 604.1 | 567.854 | 144.984 | 519.526 |
| 使用的堆平均(MB) | 434.155 | 362.46 | 114.779 | 289.968 |
| RSS内存启动(MB) | 197.7 | 159.1 | 90.5 | 57.1 |
| 最大线程数 | 77 | 47 | 73 | 42 |
| 每秒请求数 | 319 | 240 | 395 | 236 |
通过这个实验,我们可以看到Quarkus在启动时间方面比Spring Boot更快,无论是JVM版本还是原生版本。此外,Quarkus在原生映像的情况下构建时间也快得多。构建时间是91秒(Quarkus)对113秒(Spring Boot)。JVM构建时间是5.24秒(Quarkus)对1.75秒(Spring Boot),所以Spring在这个方面得分。
关于构件大小,Spring Boot和Quarkus生成的可运行构件在JVM版本方面相似,但在原生版本的情况下,Quarkus做得更好。
然而,关于其他指标,结论并不直接。让我们更深入地看看其中的一些。
5.1. CPU
如果我们关注CPU使用情况,我们将看到JVM版本在热身阶段开始时消耗更多的CPU。之后,CPU使用稳定,所有版本的消耗相对相等。
这里是Spring和Quarkus在JVM和原生版本中的CPU消耗,依次为:
(Spring JVM)

(Quarkus JVM)

(Spring Native)

(Quarkus Native)

Quarkus在两种情况下都做得更好。然而,差异非常小,也可以认为是平局。另一个值得提及的点是,在图表中,我们看到的消耗基于机器中可用的CPU数量。尽管如此,为了确保我们正在强调选项而不是系统的其他部分,我们将应用程序可用的核心数量限制为三个。
5.2. 内存
关于内存,情况更加复杂。首先,两个框架的JVM版本为堆保留更多的内存,几乎相同数量的内存。关于堆使用情况,JVM版本比原生版本消耗更多的内存,但看着一对,Quarkus似乎在JVM版本中比Spring消耗略少。但是,再次强调,差异非常微小:
(Spring Boot JVM)
(Quarkus JVM)
然后,看看原生映像,情况似乎发生了变化。Spring Native版本似乎更频繁地收集内存,并保持较低的内存占用:
(SpringBoot Native)
(Quarkus Native)
另一个重要的亮点是,在RSS内存测量方面,Quarkus似乎在两个版本中都超过了Spring。 我们只在启动时添加了RSS比较,但我们也可以在测试期间使用相同的命令。
尽管如此,在这次比较中,我们只使用了默认参数。因此,没有对GC、JVM选项或任何其他参数进行更改。不同的应用程序可能需要不同的设置,我们在实际环境中使用它们时应记住这一点。
5.4. 连接点
综合考虑,两个框架都被证明是实现Java应用程序的优秀选择。
原生应用程序显示出快速和低资源消耗,使它们成为无服务器、短命应用程序以及资源消耗至关重要的环境中的理想选择。
另一方面,JVM应用程序似乎有更多的开销,但具有出色的稳定性和高吞吐量,非常适合健壮、长寿命的应用程序。
最后,所有版本在比较时都表现出色,至少对于我们的例子是这样。差异非常小,我们可以认为它们具有类似的性能。当然,我们可以争论说,JVM版本在处理重负载方面在吞吐量方面更好,同时消耗更多资源,而原生版本消耗更少。然而,根据用例的不同,这种差异甚至可能并不相关。
最后,我们应该注意到,在Spring应用程序中,我们不得不更换数据库驱动程序,因为文档推荐的那一个有问题。相比之下,Quarkus开箱即用,没有任何问题。
6. 结论
在本文中,我们比较了Spring Boot和Quarkus框架及其不同的部署模式,JVM和Native。我们还探索了这些应用程序的一些其他指标和方面。像往常一样,测试应用程序的代码和用于测试它们的脚本可以在GitHub上找到。
OK