首页
Preview

你应该在2020年选择哪个Java微服务框架?

截至2020年,Java仍然是构建Web应用程序最流行的编程语言之一,尽管它面临着来自新语言(如Go、Python和TypeScript)的激烈竞争。

在Java世界中,Spring框架已成为微服务开发的事实标准。通过Spring Boot和Spring Data等库,该框架易于使用,并允许高效且大多数情况下无痛的开发。

然而,近年来出现了一些新的框架,声称可以提高Java应用程序的启动时间和内存占用率。由于我目前正在使用Java开发基于微服务的大型应用程序,我想检查哪个Java框架最适合这样的架构。

因此,我的主要关注点将是开发的简易性以及生成的微服务的资源管理。

在资源管理方面,Spring(实际上是大多数Java平台)从来没有得到最好的声誉,特别是当涉及到单个进程所需的开销时。在应用程序服务器的时代,这不是一个主要问题,因为实例数量很少。然而,随着微服务架构的兴起,以及它们数量庞大的小实例,这变得越来越成为一个问题——或者正如Christian Lusardi最近所说的那样:

“我发现,运行在Spring Boot之上的基本Java应用程序需要至少1GB的RAM才能运行,当你开发中间件应用程序时,这没问题,但在微服务架构中,这非常糟糕!”

候选人

Spring

Spring于2003年诞生,作为对早期Java Enterprise复杂性的回应。在其核心中,Spring作为依赖注入(DI)和面向切面编程(AOP)框架开始,并演变成易于使用的Web应用程序框架。通过其广泛的文档、广泛的使用和无数的库,Spring允许开发人员高效地创建和维护应用程序,并提供了平坦的学习曲线。

Spring使用反射在运行时执行DI。因此,当Spring应用程序启动时,类路径将被扫描以查找注释类。基于此,具体对象被实例化并链接。

虽然这非常灵活且开发人员友好,但它会使启动变慢,并且会消耗大量的内存。此外,将此机制迁移到GraalVM相当困难,因为它不支持反射。

Micronaut

Micronaut是由Grails Framework的创建者于2018年推出的现代全栈微服务框架。

它提供了构建全功能微服务应用程序所需的所有工具。同时,它旨在提供快速启动和减少内存占用率。通过使用Java注释处理器在编译时而不是运行时执行DI、创建面向切面的代理并配置应用程序,实现了这个目标。

Micronaut中的许多API受到Spring和Grails的启发。这是有意为之的,并有助于快速引入新开发人员。因此,Micronaut提供了Micronaut HTTP、数据、安全和连接到各种其他技术的模块。然而,这些库的成熟度仍然落后于Spring的对应库。

Quarkus

Quarkus是Red Hat于2019年推出的基于Kubernetes的Java框架。它构建在MicroProfile、Vert.x、Netty和Hibernate等标准之上。

Quarkus的目标是通过允许更快的启动、低内存消耗和在容器编排平台中的快速扩展,使Java成为Kubernetes的领先平台。Quarkus通过使用自定义Maven插件在编译时而不是构建时(在Quarkus中,这也称为编译时引导)执行尽可能多的工作来实现这一目标。

Quarkus主要使用现有的标准技术,但它是可扩展的。然而,由于该项目仅在一年前开始,这些扩展的成熟度和兼容性并不总是清晰的。随着平台的成长,这种情况可能会改变。

Helidon MicroProfile

MicroProfile项目于2016年启动,当时尚不清楚Oracle将如何继续开发Java Enterprise。

与其前身JEE一样,MicroProfile是一个可以由各种供应商实现的规范。

自那以后,已经提出了多个这样的实现,最值得注意的是Payara Micro和Helidon MP。Payara是从GlassFish衍生出来的Jakarte EE服务器,而Payara Micro是其MicroProfile实现。Helidon是Oracle于2018年启动的运行时,提供了其自己的MicroProfile规范实现。

由于它们源于JEE,因此MicroProfile规范是成熟且文档完备的。然而,现代技术的连接器或Spring Data和Spring Security库的替代品缺乏。

此外,由于在此期间,Jakarta EE的开发(也在Eclipse Foundation内部进行)已经开始,因此MicroProfile的未来不明确。因此,这两个项目似乎很可能会合并,或者至少在未来会紧密协调。

比较框架

为了比较这些框架,我使用每个框架实现了一个简单的应用程序。示例应用程序包括用于创建、读取、更新和删除对象的REST接口以及将这些对象存储到表中的关系数据库连接器。

如果框架支持访问数据库的不同方式,则我尝试为不同的变体实现示例项目。然后,我比较了这些应用程序的性能。我使用了一个OpenJDK Docker镜像来运行这个应用程序。如果一个框架支持生成本地的GraalVM映像,我也进行了比较。此外,请查看我的文章“使用R2DBC、Micronaut和GraalVM进行响应式数据库访问”以获取更多关于GraalVM的信息。所有这些应用程序的源代码都可以在GitHub上找到。

我比较了这些应用程序在三个关键阶段的性能:

  • 实现示例应用程序有多容易?为了实现这些框架,我不得不查看文档并在平台(如Stack Overflow)上搜索信息。
  • 编译应用程序需要多长时间?我测量了执行干净构建所需的时间,包括生成Docker映像。对于GraalVM,这包括生成本地映像所需的时间。
  • 启动应用程序需要多长时间?在这里,我测量了从运行“docker up”到应用程序正确回答第一个HTTP请求所需的时间。此外,我还比较了启动后空闲应用程序的内存占用。
  • 负载:应用程序能够处理多少请求?我使用JMeter进行负载测试,并测试了应用程序的25%请求执行数据库写操作,75%请求仅执行数据库读操作。然后,我再次测量了应用程序在峰值性能时的内存占用。

我在一个拥有四个Intel Haswell CPU和15 GB内存的运行Ubuntu 19.01的Google Cloud Platform虚拟机上执行了所有测试。为避免干扰因素,所有测量都已重复多次。你可以在GitHub上找到使用的脚本以及原始数据。

结果

开发的易用性

由于我之前只了解Spring Boot,所以这有点不公平的比较。但是,当检查文档和可用的信息和示例时,Spring是目前最容易入门的框架。

Micronaut的文档做得很好,并且它具有类似于Spring和Grail的API。因此,对于Spring开发人员来说,很容易入门。

我认为,Quarkus的学习曲线有点陡峭,因为与Spring和Micronaut相比,库和API不够成熟。我特别想念易于访问的数据库。

但是,我认为Helidon明显排名最后,因为我努力使应用程序运行起来。

编译

使用OpenJDK时,所有框架的编译时间都相当类似,介于6.98秒(使用JDBC的Spring)和10.7秒(Quarkus)之间。

然而,生成本地GraalVM映像的时间相当耗时,介于231.2秒(使用JDBC的Micronaut)和351.7秒(使用JPA的Micronaut)之间。这使得本地映像在开发中基本无用,因为等待四分钟来编译一个简单的应用程序就太长了。

启动

使用Spring Data的Spring Boot应用程序平均需要8.16秒才能启动。删除JPA和Spring Data可以将其缩短至仅5.8秒。

在这里,Micronaut(使用JPA和JDBC分别为5.08秒和3.8秒)和Quarkus(5.7秒)保持了它们更短的启动时间的承诺。

只有Helidon MP比Spring更慢,平均需要8.27秒。

然而,真正的胜利者是GraalVM。本地映像的启动时间介于1.39秒(Quarkus)和1.46秒(使用JDBC的Micronaut)之间,比OpenJDK实现快得多。

启动后的内存使用情况相当相似。使用Spring Data时,Spring分配了420 MB的内存,而使用JDBC时,它分配了261 MB的内存。

使用JPA的Micronaut为262 MB,而使用JDBC则为178 MB。

在197 MB的Quarkus表现得更好。使用414 MB的Helidon MP与Spring Boot类似。

在这里,本地GraalVM映像明显优于OpenJDK实现,仅使用7 MB(Quarkus)至27 MB(使用JPA的Micronaut)的内存。

峰值性能

在负载下,Spring Boot表现相当不错,能够提供342(使用Spring Data)和216(JDBC)个请求/秒(r/s),并使用581 MB(Spring Data)和484 MB(JDBC)的内存。Helidon明显排名最后,只能提供175 r/s,同时分配超过1 GB的内存。

其他框架能够提供400 r/s(作为本地映像运行的Quarkus)至197 r/s(在OpenJDK上运行的Quarkus)。各种Micronaut实现介于两者之间,JDBC优于JPA,本地映像优于OpenJDK。

在内存使用方面,Quarkus在OpenJDK上的表现出人意料地好,仅消耗255 MB的内存。这甚至比运行为本地映像的相同应用程序还少,后者平均需要368 MB的内存。

然而,Micronaut的内存使用效率很低。在OpenJDK中运行的JPA实现平均使用880 MB的内存,这比Spring的内存使用量高出50%以上。然而,使用JDBC和本地映像有助于将Micronaut的内存占用降至367.8 MB。

结论

Simon ConnellanUnsplash上的照片

新的Java框架Micronaut和Quarkus承诺比现有框架(如Spring和MicroProfile)具有更快的启动时间和更低的内存占用。

它们确实遵循了这个承诺,但只有在空闲或负载较小的情况下才能胜任。在这些方面,它们的表现优于Spring,尤其是在与本地GraalVM映像结合使用时。然而,在负载下,它们并没有提供太多的优势,即使作为本地映像运行也是如此。在我看来,尽管 Spring 启动时性能较差,但它仍然是提供最佳开发体验的 Java 框架,因此仍然是微服务应用程序最适合的框架。

令我惊讶的是使用 Hibernate/JPA/Spring Data 的巨大成本。即使对于这个非常简单的应用程序,在内存(但也是 R/S)方面的开销也非常大。在这里,我特别喜欢 Micronaut Data 的解决方案,它可以自动生成存储库代码,无需 JPA。这确实是一些可以添加到 Spring Data 中的东西。

原生 GraalVM 映像在启动时非常快且内存效率高,但在负载下,它们并没有提供显着的优势。由于生成原生 GraalVM 存在一些额外的困难并且编译时间大大增加,因此这种技术目前只在需要快速启动的情况下有用,例如在无服务器架构或需要快速扩展时。在所有其他情况下,成本仍然太高,与负载下类似的性能相比不值一提。

资源

lizzyTheLizard/medium-java-framework-compare

Micronaut:JVM 的现代微服务框架

Helidon 项目

spring.io

Quarkus - 超音速亚原子 Java

GraalVM

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
阿波
The minute I see you, I want your clothes gone!

评论(0)

添加评论