暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

关于 Micronaut、Quarkus 和 Spring Boot 你要知道的事情

MicroGrails 2020-07-15
2707

至今,Java 仍旧是用来构建 Web 应用的最流行编程语言之一 —— 但是它不得不面对诸如 Go,Python 和TypeScript 等新语言的严峻挑战。

在 Java 世界里,Spring 框架早已成为微服务开发的事实标准。通过使用诸如 Spring Boot 和 Spring Data 这样的库,Spring 框架变得简单易用,并且大部分情况下,开发过程高效、无痛点。

然而,最近几年一些新框架不断涌现,声称可以降低 Java 应用的启动时间和内存占用。我最近一直在用 Java 去设计大型的微服务架构应用,在做设计之前,我查了哪些Java框架最合适微服务架构。

我主要关注在框架带来的易用性和资源管理。

Spring 虽然是 Java 平台最流行的框架,但是从来没有人说它是最好的框架。在资源管理这方面,尤其是单进程所需要的性能开销这块,Spring 差强人意。在应用服务器开发的旧时代,这不是一个大问题,因为进程实例数量不多。然而,随着微服务架构的崛起,我们会有大量的进程,这就使得 Spring 的这个问题更加突出 —— Christian Lusardi 最近就这么说:

“我发现就算一个简单的 Java 应用,要是用了 Spring Boot,那么至少需要 1 GB 的内存才能把它运行起来。要是开发一个中间件,这样的开销还可以接受,但是对于微服务架构来说,太糟糕了!”

可选框架

Spring

Spring是在 2003 年面世的,以应对旧时代 Java 企业级开发的复杂性。Spring 以依赖注入和面向切面编程为核心,演进成一个易用的 web 应用开发框架。Spring 有着非常多的文档,广泛的使用率和数不清的库,让开发者高效的创建和维护应用程序,并且提供了扁平的学习曲线。

Spring 通过反射在运行期间执行依赖注入。当一个 Spring applicaiton 启动时,在类路径中,被标记的类(annotated classes)会被扫描到,由此,具体的类对象被实例化和被连接。

虽然这能提升应用程序的弹性,但是也使得应用程序的启动时间变慢,并且内存开销变大。同时,这个机制使得迁移到 GraalVM 变得非常困难,因为 GraalVM 不支持反射。

Micronaut

Micronaut  是一个现代化的微服务架构框架,由 Grails 框架的作者在 2018 年开发。

它提供了所有必要的工具来创造功能全面的微服务应用。同时,它的目标是赋予应用程序快速的启动时间和更低的内存开销。这一切都发生在编译期间而非运行时,使用了 Java 注解处理器执行依赖注入,创建面向切面代理,配置应用程序。

Micronaut 的许多 API 从 Spring 和 Grails 中获得灵感。这样的设计快速吸引了新开发者的注意。Micronaut 提供了很多的模块,诸如 Micronaut HTTP、data、security 和连接其他技术的连接器。然而,就成熟度而言,Micronaut 的这些库要落后于 Spring 里对应的库。

Quarkus

Quarkus 在2019年由红帽开发,是一个 Kubernetes 原生的 Java 框架。它依托于 MicroProfile、Vert.x、Netty 和Hibernate。

Quarkus 的目标是让 Java 在容器编排环境中有着更快的启动速度,更低的内存开销和近乎瞬间的扩容伸缩能力,并期望让 Java 在 Kubernetes 环境能成为一个主导平台。为达到此目的,Quarkus 通过自定义 Maven 插件在编译期间尽可能地做更多的工作。

Quarkus 使用了大量已存在的标准技术,同时对扩展开放。然而这个项目是一年前才开始的,这些扩展的成熟度和兼容性还不明确,很有可能在将来随着平台的成长发生改变。

Helidon MicroProfile

MicroProfile 项目始于 2016 年,那时候,大家对于 Oracle 会在 Java 企业级开发这块持续发力,觉得前途未卜。

像它的先驱 JEE,MicroProfile 只是一份规范,可以被具体架构来实现。

随后,许多具体的实现出现在大家面前,其中最著名的是 Payara Micro 和 Helidon  MP。Payara 是一种起源于GlassFish 的 Jakarta 企业级服务器,也是 MicroProfile 的一个实现。Helidon 则是一个运行时,由 Oracle 公司在2018 年发起,并提供了对于 MicroProfile 规范的实现。

虽然它们都来自于 JEE,并且 MicroProfile 规范文档成熟与完善,但是缺少了针对其他现代技术的连接器或是一些必要的库来替代 Spring Data 和 Spring Security。

MicroProfile 的未来是不明朗的,与它同在 Eclipse 基金会的另一个项目 Jakarta EE,也刚刚开始发展起来。在未来,两者很有可能会合并——至少紧密关联。

框架的比较

为了对上面提及过的框架进行比较,对每一个框架,我都创建了一个简单的应用程序,程序由 REST 接口和数据库连接器组成(译:JDBC,JPA,Spring Data)。REST 接口对 objects 做增删改查操作,数据库连接器则把这些 objects 存入数据库中。

如果一个框架支持多种方式接入数据库,我会一一实现,然后对这些应用程序做性能作比较。

我把这些应用跑在 OpenJDK Docker 镜像里。如果某个框架支持对原生 GraalVM 镜像生成,我也会把这些拿来作比较。你也可以看下我的另一篇文章 “Reactive Database Access with R2DBC,Micronaut and GraalVM” 来获得更多关于GraalVM的资讯。这些源码你可以在 GitHub  上找到。

我主要从这几个关键点来比较这些应用程序的性能:

  • 有多容易去实现这些程序样例?为了能够实现这些框架,我不得不去查看相关文档,并同时在 stack overflow 这类的平台上去寻找相关信息。

  • 要编译一个程序要花多久的时间?我测量了执行一次程序构建所需要的时间,这包含了 Docker 镜像生成时间。至于 GraalVM 这类,则包含了生成原生 GraalVM 镜像所花的时间。

  • 启动一个应用程序要花多少时间?我测量了应用程序在敲下docker up
    命令之后,与它第一次能够正确响应HTTP请球之前的所需要的时间。同时我也比较了程序启动后在闲置状态下的内存占用。

  • 应用程序在高负载状态下能够处理多少请求?我使用了 JMeter 来做压力测试,其中有 25% 的请求来执行程序的写操作,另外的 75% 请求来做数据库读操作。在程序达到高负载的状态,测量它的内存占用。

我在谷歌云上面完成了所有的测试。虚拟机采用了四核的 intel Haswell 架构 CPU 和 15GB 的内存。系统则是Ubuntu 19.01。所有的测试都重复做了多次,以避免干扰因素。你可以在 GitHub,找到这些脚本和原始数据。

结论

程序开发的易用性

由于之前我已对 Spring Boot 有一些使用经验,所以这方面的比较,有一点点的不公平。然而,当你查看了 Spring 的文档,相关信息与例子后,会发现 Spring 是目前为止最容易上手的框架。

Micronaut 的文档也做得很棒,它有着与 Spring 和 Grails 类似的 API,因此,对于用过 Spring 的开发者来说也是非常容易上手的。

Quarkus 的学习曲线更陡峭一些,我认为,相较于 Spring 与 Micronaut,Quarkus 的 API 和库缺乏成熟度,尤其数据库连接方面,易用性比较糟糕。

Helidon 在易用性方面是最糟糕的,因为我花了非常大的努力才使得应用程序跑起来。

编译

所有框架只要是使用了 OpenJDK,那么编译时间是差不多的,在 6.98 秒(使用 JDBC 的 Spring 应用程序)到10.7 秒(使用Quarkus的应用程序)之间。

而原生GraalVM镜像生成的时间开销非常大,在 231.2 秒(使用JDBC的 Micronaut 应用程序)到 351.7 秒(使用 JPA 的 Micronaut 应用程序)之间。从开发过程来说,这使得原生 GraalVM 镜像变得基本无意义,因为编译一个简单的应用程序需要等待 4 分钟,这是很过分的事。

启动

使用了 Spring Data 的 Spring Boot 应用程序平均花费 8.16 秒来启动。当去除了 JPA 和 Spring Data,这个时间降到了 5.8 秒。

这里,Micronaut(使用 JPA 时,花费 5.08 秒启动,使用 JDBC 时,花费 3.8 秒)和 Quarkus(花费 5.7 秒启动)都达到了他们的承诺,可以更快的速度启动应用程序。

只有 Helidon MP 比 Spring 启动速度更慢 —— 平均要 8.27 秒。

GraalVM,在启动方面,表现最好,启动时间分别是 1.39 秒(Quarkus 应用程序)和 1.46 秒(使用了 JDBC 的Micronaut 应用程序),远远快于基于 OpenJDK 的那些实现。

程序启动后的内存使用非常相似。Spring 在使用了 Spring Data 的情况下占用 420 MB的内存,在使用了 JDBC 的情况下占用 261 MB内存。

Micronaut 在使用了 JPA 的情况下,占用 262 MB 的内存,在使用了 JDBC 的情况下占用 178 MB 的内存。

Quarkus 表现得更好一些,内存开销在 197 MB。Helidon MP 则与 Spring Boo t类似,内存开销在 414 MB。

高负载

在高负载情况下,Spring Boot 表现相当的好,在使用了Spring  Data 情况下,每秒能够处理 342 个请求,内存开销是 581 MB,在使用了 JDBC 情况下每秒能够处理 216 个请求,内存开销是 484 MB。毫无疑问地是,Helidon 在高负载状态下表现最糟糕,在高负载情况下,内存开销超过 1 GB,处理请求只有每秒 175 个。

其他的框架在高负载情况下,在 400 请求/秒(使用了原生 GraalVM 镜像的 Quarkus 应用程序)到 197 请求/秒(跑在 OpenJDK 上的 Quarkus 应用程序)之间。Micronaut 相关的实现也在这个数值之间,当 Micronaut 搭配 JDBC 时,每秒处理能力要比 Micronaut 搭配 JPA 时要稍微好一些。当 Micronaut 搭配原生 GraalVM 镜像时要比Micronaut 搭配 OpenJDK 时要好一些。

就内存使用角度而言,Quarkus 搭配 OpenJDK,出奇的好,内存开销仅要 255 MB,这要远远低于 Quarkus 搭配原生 GraalVM 镜像的时候,Quarkus 搭配原生 GraalVM 镜像时,平均开销在 368 MB。

总结

相较于 Spring 和 MicroProfile 这样现有的老框架,Micronaut 和 Quarkus 这类的新框架,有着更快的启动速度和更低的内存占用。

但是这些优势是有条件的,仅当程序在空闲状态和低负载状态下才成立,当程序用了原生 GraalVM 镜像时,这样的优势可以更加突出。但是在高负载情况下,这些优势就不明显了,即使是用了原生 GraalVM 镜像。

目前为止,我认为,Spring 仍旧是拥有着最好的开发体验,最合适于微服务应用的 Java 框架,即使它在启动速度方面表现糟糕。

让我感到惊讶的是,使用 Hibernate JPA Spring  Data,会给程序带来巨大的开销,即使是一个非常简单的程序,在使用了这些库后,对内存开销和每秒请求率影响也很巨大。在此,我特别喜欢 Micronaut Data 的解决方案,它自动生成相应代码,而不再需要 JPA。这个功能真应该加到 Spring Data 里去啊。

原生 GraalVM 镜像可以得程序在启动速度方面变得非常的快,内存效率也不错。但是当高负载情况下,就体现不出巨大的优势了。同时,原生 GraalVM 镜像也带来了额外的痛点,使得编译时间大大增加,这就让这门技术,仅在要求程序快速启动的场景下,才有意义——比如说无服务架构(Serverless)或者要求快速扩容伸缩的场景。在其他场景下,投入远大于回报。



译文来自:http://dockone.io/article/9765?utm_source=tuicool&utm_medium=referral

原文来自:https://medium.com/better-programming/which-java-microservice-framework-should-you-choose-in-2020-4e306a478e58

Micronaut:https://micronaut.io/

Quarkus:https://quarkus.io/

https://github.com/lizzyTheLizard/medium-Java-framework-compare/tree/master/compare


文章转载自MicroGrails,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论