在容器时代(“ Docker时代”),Java仍然活着,不管是否努力奋斗。 谁会赢:Spring Boot或Quarkus。

谁会赢? Spring Boot或Quarkus。

在容器时代(“ Docker时代”),Java仍然活着,不管是否努力奋斗。 Java一直以其性能着称,主要是因为代码和真实机器之间的抽象层,多平台的成本(编写一次,可以在任何地方运行-记住这一点吗?),其中包含JVM。 -between(JVM:模拟真实计算机执行功能的软件计算机)。

通过优锐课的java学习分享,如今,使用微服务架构可能不再有意义,也没有任何优势,而是为始终在相同位置和平台(Docker容器-Linux环境)上运行的东西构建多平台(解释)的东西。 可移植性现在不再那么重要了(也许比以往任何时候都重要),那些额外的抽象级别并不重要。

话虽如此,让我们在两个备选方案之间进行简单的原始比较,以在Java中生成微服务:非常知名的Spring Boot和不太熟悉的Quarkus。

对手
谁是 Quarkus?

一套适用于GraalVM和HotSpot的开源技术,可以编写Java应用程序。 它提供(承诺)超快速的启动时间和更低的内存占用。 这使其非常适合容器和无服务器工作负载。 它使用Eclipse Microprofile(JAX-RS,CDI,JSON-P)(Java EE的子集)来构建Microservices。

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

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

我们进行的主动静态分析需要一个封闭世界的假设,这意味着在构建时必须知道运行时可访问的所有类和所有字节码。

因此,例如,反射和Java本机接口(JNI)将无法使用,至少是开箱即用的(需要一些额外的工作)。 你可以在此处的Native Image Java限制''文档中找到限制列表。
谁是Spring Boot?

真? 好吧,只说一句话(随意跳过):Spring Boot是建立在Spring框架之上的开源框架,它提供了一种更简单的方法来构建,配置和运行基于Java Web的应用程序 。 使之成为微服务的理想选择。

准备-创建Docker映像
夸库斯图像

让我们创建Quarkus应用程序,以便稍后将其包装在Docker Image中。 基本上,我们将执行Quarkus入门指南中的相同操作。
使用Quarkus maven原型创建项目:

Dockerfile
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 App Image,另一个用于本机App Image。
在生成的代码中,我们只需要更改一件事,在下面添加依赖项,因为我们要生成JSON内容。

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

在整个RESTEasy项目实施过程中,Quarkus使用JAX-RS规范。
仅此而已,使用下一条命令,我们可以看到应用程序正在运行:

Dockerfile
mvn clean compile quarkus:dev

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

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

现在我们看到它正在运行,让我们创建Docker Image。

重要! 不要下载最新版本19.3.0,因为它与Quarkus 1.0不兼容,也许会与Quarkus 1.1兼容。 现在,应该工作的版本是GraalVM 19.2.1,得到这个。
配置其环境变量起始路径:

Dockerfile

At macOS will be: export

GRAALVM_HOME=/Users/ualter/Developer/quarkus/graalvm-ce-java8-19.2.1/Contents/Home/

然后在你的环境中为GraalVM安装本机映像:
Dockerfile

$GRAALVM_HOME/bin/gu install native-image

让我们为当前平台生成本机版本(在这种情况下,将为macOS生成本机可执行文件)。

Dockerfile

mvn package -Pnative

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

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

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

此时,请确保具有Docker容器运行时和可运行的环境。
该文件将是64位Linux可执行文件,因此自然地,此二进制文件不适用于我们的macOS,它是为我们的Docker容器映像构建的。 因此,继续前进...让我们继续进行Docker映像生成...

Dockerfile
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启动映像

在这一点上,可能每个人都知道如何生成普通的Spring Boot Docker映像,让我们跳过细节吧? 只是一项重要的观察,代码是完全相同的。 更好的说法是几乎一样,因为我们当然使用的是Spring框架注释。 那是唯一的区别。

The Battle

让我们启动两个容器,使其启动并运行几次,然后比较启动时间和内存占用量。

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

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

关于无服务器架构,在此模型中,通常,临时容器将由事件触发以执行任务/功能。 在云环境中,价格通常基于执行次数而不是先前购买的某些计算能力。 因此,此处的冷启动可能会影响此类解决方案,因为容器(通常)仅在执行任务时才处于活动状态。

在“可伸缩性”中,很明显,如果有必要突然进行横向扩展,则启动时间将定义直到容器完全准备就绪(启动并运行)以响应所提出的加载方案之前所花费的时间。
这种情况(需要且快速)突然增加了多少,长时间的冷启动情况可能更糟。

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

好吧,你可能已经注意到,它是在启动时间图中插入的另一项经过测试的选项。 实际上,它与Quarkus应用程序完全相同,但是是使用JVM Docker Image(使用Dockerfile.jvm)生成的。 如我们所见,甚至使用Docker镜像和JVM Quarkus应用程序的应用程序的启动时间也比Spring Boot快。

不用说,显然是获胜者Quarkus Native应用程序,它是迄今为止所有人中启动速度最快的应用程序。

内存占用
现在,让我们检查一下内存如何运行。 检查每个容器应用程序在开始时需要消耗多少内存,以使其自身启动并运行,以准备接收请求。

结论
总结一下所有事情,这就是我们在Linux Ubuntu中查看结果的结果:

看来Quarkus赢得了这两轮比赛(启动时间和内存占用),以明显的优势战胜了对手SpringBoot。

这可能使我们感到疑惑……也许是时候考虑一些真正的实验室,经验以及对Quarkus的一些尝试了。 我们应该了解它在现实生活中的表现,它如何适合我们的业务场景以及最有用的东西。

但是,让我们不要忘记其弊端,因为我们已经在上面看到了JVM的某些功能在本机可执行二进制文件中无法(尚未/轻松)运行。 无论如何,可能是时候给Quarkus一个证明自己的机会了,特别是如果冷启动的问题一直困扰着你。 如何在环境中使用一台或两台装有Quarkus的Pod(K8),如何看待一段时间后的性能会很有趣,不是吗?

喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
 > 如果你对java技术很感兴趣也可以交流学习,共同学习进步。 
不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干货

微服务:Quarkus与Spring Boot