低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

红帽为何要推出基于云原生的编程框架 Quarkus

2020 年 6 月 01 日

红帽为何要推出基于云原生的编程框架 Quarkus

导读:随着各种开放云平台的出现,传统的基于 Java 和 J2EE 的编程模型和框架在云环境下无法适应,高内存需求和启动速度缓慢等限制了它们在云平台的扩展能力,面向云原生的编程框架需求变得越来越多。2019 年红帽发布了基于云原生的 Java 框架 Quarkus,本文作者冯征从 Quarkus 项目背景、设计特色、应用场景、开发难点等方面做了全方位剖析,希望给关注 Quarkus 框架的开发者带来一些帮助和思考。他还将在 QCon 全球开发大会(北京站)2020 分享 Quarkus 的更多技术动态,敬请关注!


Quarkus 项目背景

2018 年,在一次内部会议中,有人问到“有什么会成为红帽中间件最大的威胁?”,红帽中间件副总裁 Mark Little 的回答让我印象很深。他最担心的事情是,如果一种新的编程语言(比如 Go)能够给用户提供更快地运行速度,并且提供更丰富的类库来支持从 Java 应用的迁移,那么在云环境不断完善并进入用户的生产系统后,这种应用替换和迁移的代价在不断降低,使得用户会更倾向于使用新的编程语言来进行开发。而红帽所有基于 Java 的中间件产品都用新的编程语言来重构一遍几乎是不可能的。所以我们必须要让 Java 更快一些。


后来,红帽内部建立了一个“秘密”项目 Protean ,也就是 Quarkus 早期的名称。当时只有少数的开发人员参与设计并开发原型系统。早期测试的时候,我们在 Kubernetes 中单纯利用 Wildfly 或者 JBoss EAP 的 Docker 镜像来启动用户的应用,最多只能扩展到 100 多个实例,而且启动的时间很长。而利用 Quarkus 产生的 Native 应用 Docker 镜像,可以轻松地扩展到 1000 多个示例,是前者的 10 倍多,并且启动时间大大缩短。这些都促使红帽中间件在 Quarkus 的创新,使之成为红帽整个 Open Hybrid Cloud Strategy(开放混合云架构)中重要和不可或缺的一部分。


Quarkus 与 Spring 等主流框架的异同

Quarkus 是基于 J2EE( Jakarta EE )和 MicroProfile 标准来作为技术栈,而 Spring 有自己的一套东西,大家可以从 https://simply-how.com/ Quarkus -vs-spring 来看两者的区别。其实 Spring 社区也开始在实践用 Graal VM 来构建 Native 应用,项目网站是https://github.com/spring-projects-experimental/spring-graal-native。我们可以看到,目前这个项目还是处于验证阶段,和 Quarkus 相比还有很远的距离。



Quarkus 设计特色

从一开始, Quarkus 就围绕容器优先理念进行设计。通过以下方式针对低内存使用量和快速启动时间进行了优化:


  • 对 Graal / SubstrateVM 的支持


这一直是 Quarkus 设计的重要组成部分。当把应用程序编译为本地映像时,它的启动速度会更快,并且可以用比标准 JVM 小得多的堆栈参数来运行。 Quarkus 已经通过了 Substrate 的所有测试,可以在没有 -H:+ ReportUnsupportedElementsAtRuntime 标志的情况下运行。


  • 构建阶段的元数据处理


在构建阶段将进行尽可能多的处理,因此应用程序将仅包含运行时实际需要的类。在传统模型中,所有的类都会在应用程序初始化时进行处理,即使它们仅使用一次。而使用 Quarkus ,它们甚至都不会加载到运行时的 JVM 虚拟机中。 因为在构建阶段我们就尽量完成初始化的工作,这将减少应用在运行时的内存使用量,并缩短应用的启动时间。


  • 减少反射使用


Quarkus 尽可能避免使用 Java 的反射功能。


  • Native 原生应用的提前引导


当使用 Native 原生应用运行时, Quarkus 在 Native 映像的构建过程中提前引导尽可能多的框架代码。这意味着生成的 Native 映像已经执行了大多数启动代码,并将结果序列化到最终的可执行映像文件中,从而使应用的启动速度更快。


Quarkus 的内核是围绕着 CDI 设计,整个核心就是一个微型的 CDI 容器,而且完全支持异步的编程模型比如 Netty 和 Vert.x ,可以支持直接利用 Kotlin 语言进行开发。整个 Quarkus 框架采用了 Extensions 进行扩展,其中包含了目前红帽中间件大部分的产品,比如 Hibernate ORM、 Artemis、Resteasy、Undertow、Narayana、 Infinispan、Camel、KeyCloak 等等。所以对用户来说,是可以轻松的利用这些框架和工具来进行开发。


从内部的 Quarkus 0.1 测试版本开始,到目前刚刚发布 1.4.1.Final , Quarkus 的开发速度是很快的,不断带来更多的 Extension 扩展来丰富功能。值得注意的是,从 Quarkus 1.4 版本开始,JDK 8 将被标记为过时,而从 1.6 版本开始, Quarkus 将不再支持 JDK 8,而会支持 JDK 11 的 LTS 版本。


Quarkus 应用场景

Quarkus 主要应用场景是开发云原生应用,用户可以轻松利用 Quarkus 生成 Native 映像并进行部署。当然, Quarkus 不仅仅可以运行在 Kerbenetes 环境中,也可以运行在 JVM 虚拟机环境中,甚至可以运行在用户本地的 IDE 开发环境中。它解决的核心问题是加速 Java 程序的启动和运行速度以及更小的运行时内存占用。用户非常惊叹 Native 应用的启动速度,往往能比正常的 Java 应用快 10 倍以上。而且经过优化以后, Native 的映像文件可以做的很小,非常适合在云环境中使用。


我们来看一下内存使用和启动速度的比较:



Quarkus 开发难点

其实 Quarkus 有很多的脚手架工具来帮助用户搭建开发环境,用户也可以从网站 code. quarkus .redhat.com 来轻松的生成项目工程。开发者利用 Maven 或者 Gradle 来构建应用也是非常的方便。如果要说最难的地方的话,可能会是开发 Quarkus 的 Extension 扩展。我目前的工作就是把 Camel 的组件加入到 Quarkus 中成为扩展,这样用户就可以方便的在 Quarkus 应用中使用这些 Camel 组件。


我会通过一个具体的示例来说明如何进行 Quarkus 的扩展开发。目前 Quarkus 还不支持 Scratch 方式来构建扩展项目,所以只能是在 Quarkus 的代码树中来新增扩展。比如我们想要加一个新的扩展 Upper-extension ,它可以提供应用调用的方法 Upper.convert(String str)把字符串 str 全部转换成大写:


public class Upper {    public String convert(String str) {        return StringUtils.upperCase(str);    }}
复制代码


首先我们需要从 Github 下载或者复制 Quarkus 源代码:


git clone https://github.com/quarkusio/quarkus.gitcd quarkuscd extensionsmvn io.quarkus:quarkus-maven-plugin:1.4.2.Final:create-extension -N \    -Dquarkus.artifactIdBase=upper \    -Dquarkus.artifactIdPrefix=quarkus- \    -Dquarkus.nameBase="Upper Extension"
复制代码


生成的 Maven 工程包含两个子项目 Deployment 和 Runtime 。我们来分别看看这两个子项目,首先在 Deployment 中主要包含 Quarkus 在构建阶段所需要做的工作,带有 @BuildStep 注解标记的方法都会在构建阶段执行,比如在 UpperProcessor.java 文件中


@BuildStepFeatureBuildItem feature() {    return new FeatureBuildItem(FEATURE);}
复制代码


这表明会返回一个包含当前扩展名称的 BuildItem。


各个构建步骤之间可以通过 BuildItem 来传递信息,比如上面的 FeatureBuildItem 当有其它的构建步骤需要获得这个信息的时候可以作为参数来使用:


@BuildStepvoid printFeatures(List<FeaturesBuildItem> features) {     foreach(FeatureBuildItem feature : features) {         System.out.println(feature.getInfo());     }}
复制代码


我们需要在 deployment/pom.xml 中使用如下代码处理这些 @BuildStep 注解标记的方法:


<plugin>    <groupId>org.apache.maven.plugins</groupId>    <artifactId>maven-compiler-plugin</artifactId>    <configuration>        <annotationProcessorPaths>            <path>                <groupId>io.quarkus</groupId>                <artifactId>quarkus-extension-processor</artifactId>                <version>${quarkus.version}</version>            </path>        </annotationProcessorPaths>    </configuration></plugin>
复制代码


那么如何在构建阶段创建类并实现静态初始化操作呢 ?在这里我们就需要用到 Bytecode Recording(字节码记录)。


在 Runtime 子项目中新建一个 UpperRecorder.java :


@Recorderpublic class UpperRecorder {    public void createUpper(BeanContainer container) {        Upper upper = new Upper();        container.instance(UpperProducer.class).setUpper(upper);    }}
复制代码


注意这里的 @Recorder 注解标记, Quarkus 会把构建阶段每次的方法调用都序列化,并通过生成 Bytecode 的方式保存下来。所以 CreateUpper 方法中的操作在构建阶段都不会立即执行,而是会转换成 Bytecode 并延迟到运行时再执行。


而在构建阶段,我们可以做的初始化工作,包括设置参数,扫描特定的 Annotation 并注册(我们在 Camel- Quarkus 中也使用了)等等。这样做的好处是在构建阶段可以尽量多的完成初始化工作,这样运行时启动应用的速度会大大加快。如果是要通过 Graal VM 生成 Native 映像的话,有些初始化工作是不能在构建阶段做的,比如监听网络端口,启动线程池等等。


回到 Deplolyment 的 UpperProcessor 中,我们增加一个构建步骤来创建 Upper :


@BuildStep@Record(ExecutionTime.STATIC_INIT)void create(UpperRecorder recorder, BeanContainerBuildItem beanContainer) {    recorder.createUpper(beanContainer.getValue());}
复制代码


这样我们基本完成了 Upper 扩展,为了让用户可以在 CDI 环境中使用 Upper,我们还需要在 Runtime 中新建 UpperProducer.java :


@Singletonpublic class UpperProducer {    private volatile Upper upper;    void setUpper(Upper upper) {        this.upper = upper;    }    @Produces    Upper getUpper() {        return upper;    }}
复制代码


然后在 deployment/UpperProcessor.java 中加入:


@BuildStepAdditionalBeanBuildItem upper() {    return AdditionalBeanBuildItem.unremovableOf(UpperProducer.class);    }}
复制代码


使得 Quarkus 把 UpperProducer 也当成 CDI Bean 来处理,可以在依赖注入中使用 Upper 。


最后用户就可以在应用中这样来使用:


@ApplicationScopedpublic class MyService {    @Inject    Upper upper;    public String onMessage(String message) {        return upper.convert(message);    }}
复制代码


总的来说,在 Extension 的扩展中,我们使用 @BuildStep 来标记各种构建步骤,并且尽量在构建阶段完成初始化工作,这样可以减少通过 Graal VM 生成的可执行映像文件大小,加快应用的启动速度,缩短启动时间。


Quarkus 进展与展望

很多公司在早期的 Tech Pre 版本开始就在关注 Quarkus ,比如(Ericsson、Amadeus)。随着 Quarkus 正式 GA 产品的发布,我相信会有很多的公司加入到 Quarkus 中。红帽一直以来的都坚持采用“社区驱动”的产品开发模式,未来,红帽中间件的所有产品都计划考虑加入到 Quarkus 中,这样可以让用户之前基于 J2EE 开发的应用能够在 Quarkus 中进行测试。


云原生应用越来越重要,大量基于 Java 开发的应用都面临着同样的问题,比如在云环境中如何快速的部署和提高应用启动速度。Quarkus 是红帽开放混合云战略的重要组成部分,也是红帽中间件下一代的核心产品。作为云原生应用的开发利器,Quarkus 将帮助用户利用 Jakarta EE 和 MicroProfile 技术栈更快和更便利的开发产品,并快速部署到云环境中。作为 Java 开发者,需要对云原生应用有更多的了解,并对 Quarkus 这样的新框架熟悉掌握,最后也希望能够有更多的开发者关注 Quarkus 并积极参与到社区里。我们期待推出的产品是经过社区用户的大量反馈,并且也能真正适应开发者需求的。


作者介绍:


冯征,红帽 JBoss 中间件团队高级软件工程师。2009 年加入红帽,有 10 余年的开发经验,作为核心成员参与 JBossTM 事务管理器(Narayana)的开发。目前在 JBoss Fuse 团队做 Camel 项目的研发工作,在上游的开源项目(Narayana、WildFly、Camel、CXF、Camel-K、Camel- Quarkus )中也做过贡献。




QCon北京2020的演讲中,冯征老师将介绍 Quarkus 框架设计和特点,利用 Quarkus 进行应用开发、利用 Native 模式在云平台进行部署的实践案例。点击了解更多。


2020 年 6 月 01 日 16:061778
用户头像
Kitty 极客邦科技会议主编

发布了 27 篇内容, 共 97849 次阅读, 收获喜欢 34 次。

关注

评论

发布
暂无评论
发现更多内容

redis工作原理(下)

Sakura

28天写作 28天挑战 3月日更 21天挑战

RPA助力证券行业高质量发展

Jason Tien

RPA 金融科技 证券 云原生微服务 自动化平台

正则表达式.05 - 匹配模式

insight

正则表达式 3月日更

垃圾代码和优质代码的区别?

xcbeyond

Java 优化代码 3月日更

容器 & 服务:Kubernetes构件及Deployment操作

程序员架构进阶

Docker Kubernetes 容器技术 28天写作 3月日更

Elasticsearch 定制 Dynamic Mapping 策略

escray

elastic 28天写作 死磕Elasticsearch 60天通过Elastic认证考试 3月日更

Python 关键字

HoneyMoose

熬夜重构了IDEA插件Toolkit(整合程序员常用的工具箱),更加便捷

Silently9527

Java idea插件 程序员工具、

手写的第一个 Java 应用程序,执行的时候发生了什么?

白色蜗牛

Java

为什么 HashMap 的加载因子是0.75?我研究源码发现一个重大秘密。。。

云流

程序员 架构 面试

03|PPT教程|这个课程主要讲什么?

青城

PPT PowerPoint 3月日更

翻译:《实用的Python编程》04_03_Special_methods

codists

Python

常见 git 需求整理(持续更新中)

blueju

git 前端 工具 npm

RabbitMQ集群简介

Kylin

读书笔记 RabbitMQ 消息队列 3月日更 集群简介

神了!华为18级专家把困扰我多年的操作系统与网络,讲明白了

云流

程序员 架构 计算机

2021最新腾讯面经分享:Java面试核心点/技术笔记/学习视频(春招必备)

比伯

Java 编程 程序员 架构 面试

B端产品经理自我认知

lenka

3月日更

翻云覆雨——前景理论之隔离效应

Justin

心理学 28天写作 游戏设计

SICP 习题解答 1.11

十元

调整好心态

Nydia

算法攻关 - 重建二叉树 (O(n))_0105

小诚信驿站

刘晓成 小诚信驿站 28天写作 算法攻关 重建二叉树

Spring Boot工程结构

韩斌

Spring Boot

初学者思维 - 找到解决问题的新方法

石云升

程序员成长 思维模型 28天挑战 3月日更 初学者思维

Vue源码学习 | 4个实用的javascript技巧

devpoint

Vue vuejs stringify

(28DW-S8-Day18) 可插拔式知识

mtfelix

28天写作

广告主营销策略的改变,为什么总离不开户外媒体?

󠀛Ferry

七日更 3月日更

微服务想用好,得把分布式和微服务之间的关系搞清楚

读字节

分布式 微服务 微服务架构 SpringCloud 分布式架构

Webpack 基石 tapable 揭秘

vivo互联网技术

前端 webpack 流程管理 tapable

每日打卡1:删除字符串中的所有相邻重复项

骆俊

七日更 3月日更

第9周课后练习-性能优化三

潘涛

架构师训练营 4 期

阿里大牛亲码1222道Java岗面试真题!(2021全彩版)

程序员小毕

Java 程序员 架构 面试 分布式

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

红帽为何要推出基于云原生的编程框架 Quarkus -InfoQ