夸克开源项目分析--对软件开发生态的促进作用

Jeff Zhang | March 12, 2019

夸克开源项目介绍

红帽公司中间件团队在3月7日正式发布了Quarkus项目。 Quark(夸克)是物理学名词,可以看成是最小粒子,如元素周期表序数为1的氢原子,含有一个质子,也是由3个上下夸克组成的。 所以Quarkus这个名称,应该有微小服务的含义。

Java应用适应Cloud Native

在当前云计算微服务逐渐占据互联网软件开发主流的背景下,在云上部署的软件应用有两个硬指标:

  1. 较少的内存占用 云计算资源中,最难以共享的就是内存了。CPU和带宽是比较容易分时划片的,海量存储相对廉价。但对于内存来说,基本是虚拟机独占方式分配。 而按容器部署的应用,内存会消耗的更快。Java语言编写的程序,其footprint,也就是启动后的进程占用的内存量是比较大的,这个是由于Java语言自身的特性决定。

  2. 快捷的启动速度 比起传统企业应用,在云计算环境下,软件的更新和扩展都有更快更高的需求。当用户访问请求进来到网关,通过软件路由时,云平台才会启动一个软件服务进程来响应请求。 这就需要软件进程快速启动,并做出基本回应,否则长时间的停顿会造成很差的用户体验。 Java语言有非常强劲的动态特性,常用开发框架都会在启动和运行时进行动态加载和反射操作等处理,这样写成的程序启动就绪所需要的时间就比较长。

因为上面两点主要原因,就使得Java在云原生开发上处于不利地位。 所谓原生本地应用,就是程序编译成操作系统二进制执行程序,比如C/C++开发的系统应用。Go语言作为新型语言,具备很多新的特性,也可以编译成本地代码,所以Go语言在近年来成为云计算相关软件项目的主力语言。

我们知道,和纯粹解释性执行的动态语言相比,Java语言其实是有编译阶段的。Java源程序通过javac编译成与平台无关的二进制class机器码,然后再通过java来运行。执行过程中,为了做到速度和效率的最优化,java虚拟机采用先解释执行,再局部优化编译执行,通过编译器强力优化后就是机器二进制代码了。这就是经典的JIT(Just in time)虚拟机运行机制。 相对应的编译过程为AOT(ahead of time),即事先进行编译,比如GCC编译器提前编译C语言程序。

Java在AOT编译方面一直在努力,目前的成果就是令人瞩目的GraalVM项目,可以通过native-image工具将java应用转换为本地原生应用。

Quarkus就是使用GraalVM项目来让Java应用拥抱云计算的。

性能指标

夸克项目官网上,就给出一幅醒目的性能比较图。其中包含了两个范例性能测试。

quarkus性能比较

REST是提供Rest服务的程序,REST+JPA是集成了JPA访问数据库,提供Rest服务的程序。后者包含的组件要多一些。

Quarkus分为两种执行方式,一种是通过Java虚拟机执行(Quarkus+OpenJDK),另一种是通过编译成本地代码执行(Quarkus+GraalVM)。 还有一种执行方式是传统的“云原生”技术栈(Traditional Cloud-Native Stack)。

对于REST应用,内存占用分别是13M,74M和140M,启动速度分别为0.014秒,0.75秒和4.3秒。REST+JPA也是类似的数据数值分布。对比来看,显然Quarkus的应用有极大的优势。

我也在工作机器上做了测试,编译getting-started-native应用,分别得到runner jar包和native程序。分别启动,并用time工具查看:

$ time java -jar quarkus-quickstart-runner.jar
2019-03-10 11:23:14,546 INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.556s. Listening on: http://127.0.0.1:8080
2019-03-10 11:23:14,548 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
2019-03-10 11:23:23,921 INFO  [io.quarkus] (main) Quarkus stopped in 0.030s

real	0m10.062s
user	0m1.268s
sys	0m0.156s

$ time ./quarkus-quickstart-runner 
2019-03-10 11:03:15,495 INFO  [io.quarkus] (main) Quarkus 0.11.0 started in 0.006s. Listening on: http://127.0.0.1:8080
2019-03-10 11:03:15,495 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy]
2019-03-10 11:03:17,151 INFO  [io.quarkus] (main) Quarkus stopped in 0.001s

real	0m10.381s
user	0m0.008s
sys	0m0.015s

可以看到java虚拟机启动时长为0.556秒,服务一段时间后停止,停止用时0.03秒,期间用户态(user)为1.268秒,内核态(sys)0.156秒。 而本地程序启动时长为0.006秒,停止用时0.001秒!期间用户态为0.008秒,内核态0.015秒。

再使用time -v看一下保留内存使用量

$ /usr/bin/time -v java -jar quarkus-quickstart-runner.jar
...
	Maximum resident set size (kbytes): 103604

$ /usr/bin/time -v ./quarkus-quickstart-runner 
...
	Maximum resident set size (kbytes): 14120

分别是103M和14M内存占用。

和官网给出的测试结果性能比较是一致的。Quarkus这个项目太棒了!

标准技术

Quarkus项目是一个Java项目,基于JavaEE和Microprofile的部分规范。

其中核心是经过部分裁剪的CDI规范,用来进行组件注入,组件生命周期管理和事件捕获。 所支持的JavaEE规范中,Servlet可以部署web应用,JaxRS暴露Rest服务,JPA提供对象数据到关系数据库中的映射能力。 另外可以用BV规范进行组件数据的统一校验,可以使用JsonB和Jaxb进行数据的序列化操作。

Microprofile规范中,核心使用的是config规范,即统一定义配置项。对于微服务应用来说,配置项的定义和使用是重要的开发考虑因素。 其他使用的Microprofile规范有OpenTracing, OpenAPI, JWT, REST Client, Reactive Messaging, FaultTolerance, Health, Metrics等等。可以看成是和SpringCloud的对应组件。

Quartus中集成的重要组件有:

  • Hibernate,提供JPA能力,进行ORM映射。
  • Resteasy,提供Rest数据发布能力,JaxRS规范实现。
  • Undertow,提供Web服务器和Servlet实现,以及支持Websocket。
  • Vertx,集成使用,提供ReactiveStream数据。
  • Camel,数据集合转换能力和DSL解释。
  • Smallrye,提供Microprofile规范API实现。
  • SubstrateVM,GraalVM子项目,用来帮助native镜像生成。
  • Elytron,安全组件,提供SSL,证书管理,用户管理等功能。

另外还集成了Netty, Infinispan, Kafka, Nayarana等。

Quarkus核心中,包含了自行开发的CDI规范实现Arc项目,用来管理组件,解析组件之间的关系,进行注入和生命期管理。 另外还有一个自研项目Gizmo,进行字节码写入。 Quarkus充分利用了Maven的构建组装能力。项目提供了maven插件进行编译,测试,运行,动态调试,二进制程序生成等全部开发能力。也可以使用Gradle进行构建。

尝试使用过GraalVM生成本地程序的朋友会知道,Java机器代码转换为本地代码,有若干困难点。

主要包括:动态类加载(Dynamic Class Loading),反射(Reflection),动态代理(Dynamic Proxy),JNI,不安全的内存访问(Unsafe),动态调用方法(InvokeDynamic)等等。

Quarkus定义了一套数据模型来定义这些,在编译构建时告知Java编译器哪些Java代码需要进行处理,替换,重写甚至移除,从而保证应用程序没有“非友好”的动态代码调用方式。 也进一步使生成二进制本地代码成为可能。每一个组件都分为Runtime和Deployment两个处理阶段,即运行时阶段和部署阶段,由Quarkus内核运行,以及“部署”写成本地执行代码。

Quarkus生成的“云原生”应用,可以完美的运行在容器环境之中,这也是这个项目最终的目的。

Kubernetes可以很好进行资源调度,Quarkus应用程序可以作为微服务应用,也可以进行流式处理,数据转换,高强度计算。

我能感觉到Quarkus在设计时,就充分的考虑了为适应Kubernetes而做了不少工作。应用构建可以配合Knative的build过程,可以直接生成docker文件。配置信息和状态信息的使用和管理,也是容器友好的。不难想到这个项目会成为红帽容器化业务openshift重要的组成一环。

由于篇幅和时间关系,更多的技术内容就不再本文中展开了。 后续随着项目的逐步成熟,我会逐步按照以下纲要完善技术内容,未来提供一门技术培训课程,和业内朋友继续交流。我们也会使用Quarkus来开发适合的软件应用产品。

附:技术分析纲要

JavaEE部分规范
Microprofile技术规范

经过裁剪的CDI实现, Arc
Configuration
日志能力

Maven组装能力 Build Step
字节码记录
GraalVM
NativeImage
Runtime和Deployment
SVM(substrate, remove reflection, substitutions)

Rest
Servlet
Websocket
Validatior

JDBC
ORM
Panche
JTA
Datasource

Scheduler
Infinispan
Reactive Message
Vertx

Elytron Security
JWT

OpenTracing
Metrics
Fault Tolerance

和K8S的配合
容器化
Knative