微服务架构之争:Quarkus VS Spring Boot

2023-12-16 12:45

本文主要是介绍微服务架构之争:Quarkus VS Spring Boot,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在容器时代(“Docker时代”),无论如何,Java仍然活着。Java在性能方面一直很有名,主要是因为代码和真实机器之间的抽象层,多平台的成本(一次编写,随处运行——还记得吗?),中间有一个JVM(JVM:模拟真实机器的软件机器)。

如今,有了微服务架构,也许它不再有意义,也没有任何优势,为总是在同一地方和平台上运行的东西Docker 容器 — Linux 环境)构建多平台(解释)的东西。可移植性现在不那么重要了(也许比以往任何时候都更重要),那些额外的抽象级别并不重要。

话虽如此,让我们对在 Java 中生成微服务的两种替代方案进行简单而原始的比较:非常著名的 Spring Boot 和不太知名的 Quarkus

对手

Quarkus

Quarkus

一套适用于GraalVM和HotSpot的开源技术,用于编写Java应用程序。它提供(承诺)超快的启动时间和更低的内存占用。这使其成为容器和无服务器工作负载的理想选择。它使用 Eclipse Microprofile(JAX-RS、CDI、JSON-P)来构建微服务,这是 Java EE 的一个子集。

GraalVM 是一个通用的多语言虚拟机JavaScript、Python、Ruby、R、Java、Scala、Kotlin)。 GraalVM(特别是 Substrate VM使提前 (AOT) 编译成为可能,将字节码转换为本机机器码,从而生成可以在本机执行的二进制文件

请记住,并非每个功能在本机执行中都可用,AOT 编译有其局限性。注意这句话(引用GraalVM团队的话):

我们运行一个积极的静态分析,它需要一个封闭世界的假设,这意味着在运行时可以访问的所有类和所有字节码都必须在构建时是已知的。

因此,例如,反射和 Java 本机接口 (JNI) 将不起作用,至少是开箱即用的(需要一些额外的工作)。您可以在此处找到限制列表本机映像 Java 限制文档。

Spring Boot

SpringBoot

不用多介绍了,用一句话说(随意跳过它):Spring Boot 建立在 Spring Framework 之上,是一个开源框架,它提供了一种更简单的方法来构建、配置和运行基于 Java Web 的应用程序。使其成为微服务的良好候选者。

战斗准备 — 创建 Docker 镜像

Quarkus 镜像

让我们创建 Quarkus 应用程序,稍后将其包装在 Docker 映像中。基本上,我们将执行与Quarkus入门教程相同的操作。

使用 Quarkus maven 原型创建项目:

mvn io.quarkus:quarkus-maven-plugin:1.0.0.CR2:create \ -DprojectGroupId=ujr.combat.quarkus \  -DprojectArtifactId=quarkus-echo \ -DclassName="ujr.combat.quarkus.EchoResource" \-Dpath="/echo"

这将项目的结构,如下所示:

请注意,还创建了两个示例 Dockerfile (src/main/docker):一个用于普通 JVM 应用程序映像,另一个用于本机应用程序映像

在生成的代码中,我们只需要更改一件事,添加下面的依赖项,因为我们想要生成 JSON 内容。

<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jsonb</artifactId> 
</dependency>

Quarkus 在整个 RESTEasy 项目实现中使用 JAX-RS 规范。

这是我们的“完整”应用程序:

仅此而已,通过下一个命令,我们可以看到应用程序正在运行:

mvn clean compile quarkus:dev

在这种模式下,我们还启用了热部署,并带有后台编译。让我们做一个简单的测试来看看它:

curl -sw "\n\n" http://localhost:8080/echo/ualter | jq .

现在我们已经看到它正在工作,让我们创建 Docker 映像。从此处下载 GraalVM:Releases · graalvm/graalvm-ce-builds · GitHub。

重要! 不要下载最新版本 19.3.0, Quarkus 1.0 它与它不兼容,也许 Quarkus 1.1 会。现在应该可以运行的版本是 GraalVM 19.2.1,获取这个版本。

配置其环境变量主路径:

## At macOS will be: export 
GRAALVM_HOME=/Users/ualter/Developer/quarkus/graalvm-ce-java8-19.2.1/Contents/Home/

然后在您的环境中安装 GraalVM 的本机映像:

$GRAALVM_HOME/bin/gu install native-image

让我们为当前平台生成本机版本(在本例中,将为 macOS 生成本机可执行文件)。

mvn package -Pnative

如果一切正常,我们可以在 ./target 文件夹中找到一个名为的文件。这是应用程序的可执行二进制文件,您可以运行以下命令启动它:.无需使用 JVM(普通:java -cp app:lib/*:etc App.jar),它是一个本机可执行二进制文件。quarkus-echo-1.0-SNAPSHOT-runner ./target/quarkus-echo-1.0-SNAPSHOT-runner

让我们为应用程序生成一个原生 Docker 映像。此命令将创建一个本机映像,即具有 Linux 本机可执行应用程序的 Docker 映像。默认情况下,本机可执行文件是基于当前平台(macOS)创建的,因为我们知道这个生成的可执行文件与容器(Linux)的平台不同,我们将指示Maven构建从容器内部生成可执行文件,生成本机docker映像:

mvn package -Pnative -Dquarkus.native.container-build=true

此时,请确保有一个 Docker 容器运行时,一个工作环境。

该文件将是一个 64 位 Linux 可执行文件,因此自然而然地,这个二进制文件不适用于我们的 macOS,它是为我们的 docker 容器映像构建的。所以,向前迈进......让我们来生成 Docker 镜像......

docker build -t ujr/quarkus-echo -f src/main/docker/Dockerfile.native . ## Testing it... docker run -i --name quarkus-echo --rm -p 8081:8081 ujr/quarkus-echo

关于 Docker 镜像大小的旁注:

最终的 docker 镜像是 115MB,但您可以使用无发行版的镜像版本来拥有一个很小的 Docker 镜像。无发行版映像仅包含您的应用程序及其运行时依赖项,其他所有内容(包管理器、shell 或标准 Linux 发行版中常见的普通程序)都将被删除。应用程序的 Distroless 映像大小为 42.3MB。该文件具有生成它的收据。./src/main/docker/Dockerfile.native-distroless

关于Distroless Images:“ 将运行时容器中的内容限制为应用程序所需的内容是 Google 和其他在生产中使用容器多年的科技巨头采用的最佳实践"

Spring Boot 镜像

至此,大概大家都知道如何制作一个普通的Spring Boot Docker镜像了,我们先跳过细节吧?只有一个重要的观察结果,代码是完全相同的。几乎是一样的,因为我们当然使用的是 Spring 框架注解。这是唯一的区别。您可以在提供的源代码中查看每个细节。

mvn install dockerfile:build 
## Testing it...docker run --name springboot-echo --rm -p 8082:8082 ujr/springboot-echo

战斗

骰子

让我们启动这两个容器,让它们启动并运行几次,并比较启动时间和内存占用

在这个过程中,每个容器都被创建和销毁了 10 次。后来,分析了他们的启动时间和内存占用。下面显示的数字是基于所有这些测试的平均结果。

启动时间

显然,当与可扩展性无服务器架构相关时,这方面可能会发挥重要作用。

关于 Serverless 架构,在此模型中,通常由事件触发临时容器来执行任务/功能。在云环境中,价格通常基于执行次数,而不是以前购买的一些计算容量。因此,这里的冷启动可能会影响这种类型的解决方案,因为容器(通常)只会在执行其任务的时间内处于活动状态。

在可伸缩性中,很明显,如果需要突然横向扩展,启动时间将定义容器完全准备就绪(启动并运行)以响应所呈现的加载方案所需的时间。

这种情况有多突然(需要和快速),更糟糕的情况可能是长时间的冷启动

让我们看看它们在启动时间方面的表现:

好吧,您可能已经注意到,这是在“启动时间”图中插入的又一个经过测试的选项。实际上,它与Quarkus 应用程序完全相同,但使用 JVM Docker 映像(使用Dockerfile.jvm)生成。正如我们所看到的,即使是使用带有 JVM 的 Docker 映像的应用程序,Quarkus 应用程序的启动时间也比 Spring Boot 更快。

毋庸置疑,Quarkus Native 应用程序显然是赢家,它是迄今为止启动速度最快的应用程序。

内存占用

现在,让我们检查一下内存的情况。检查每个容器应用程序在启动时需要消耗多少内存,以启动并运行,并准备好接收请求。

内存占用图

结论

总而言之,这就是我们在 Linux Ubuntu 中查看的结果:

启动图形

Quarkus 似乎赢得了这两轮战斗(启动时间和内存足迹),以一些明显的优势战胜了他的对手   SpringBoot。

这可能会让我们想知道......也许是时候考虑一些真实的实验、经验和一些 Quarkus 的尝试了。我们应该看看它在真实世界中的表现如何,它如何适应我们的业务场景,以及在什么方面最有用。

但是,我们不要忘记缺点,正如我们在上面看到的,JVM的某些功能在本机可执行二进制文件中无法(还/容易)工作。无论如何,也许是时候给 Quarkus 一个证明自己的机会了,特别是如果冷启动的问题一直困扰着你。在环境中使用一两个由 Quarkus 驱动的 Pod (K8s) 怎么样,看看一段时间后它的表现会很有意思,不是吗?

这篇关于微服务架构之争:Quarkus VS Spring Boot的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/500524

相关文章

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Java编译生成多个.class文件的原理和作用

《Java编译生成多个.class文件的原理和作用》作为一名经验丰富的开发者,在Java项目中执行编译后,可能会发现一个.java源文件有时会产生多个.class文件,从技术实现层面详细剖析这一现象... 目录一、内部类机制与.class文件生成成员内部类(常规内部类)局部内部类(方法内部类)匿名内部类二、

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

Java实现文件图片的预览和下载功能

《Java实现文件图片的预览和下载功能》这篇文章主要为大家详细介绍了如何使用Java实现文件图片的预览和下载功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... Java实现文件(图片)的预览和下载 @ApiOperation("访问文件") @GetMapping("