热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【JVM技术专题】JDK/JVM的新储君—GraalVM和Quarkus

GraalVM介绍今天我们来讲讲整个Java生态下相当有分量的一位角儿——GraalVM:GraalVM官方网站,Quarku官方文档GraalVM是用




GraalVM介绍


今天我们来讲讲整个Java生态下相当有分量的一位角儿——GraalVM:GraalVM官方网站,Quarku官方文档


GraalVM是用Java实现的基于HotSpot/OpenJDK的JVM和JDK。它支持额外的编程语言和运行范式,例如对Java应用程序AOT,从而实现快速启动和低内存占用。


GraalVM的三大特点:


  • GraalVM可以代替JDK、JVM之前的工作
  • GraalVM除了支持Java,也支持多种语言
  • GraalVM可以对应用AOT,也就是把程序直接编译成二进制,从而提升启动速度、改进内存使用。

了解完这些背景知识,我们再看看官网怎么说。

Run Programs Faster Anywhere
Increase application throughput and reduce latency
Compile applications into small self-contained native binaries
Seamlessly use multiple languages and libraries

在各种地方跑起来都更快。提升应用的吞吐并减少延迟、把应用编译成独立本机的二进制程序、无缝使用多种语言和库。



  • 性能有多强
  • 多语言互相调用好使不
  • 编译二进制香不香



性能有多强


GraalVM框架的测试表现供大家参考,数据有点夸张哈,但是大趋势肯定是不会错的。


  • 横轴表示时间,可以明显看出在GraalVM的加持下,Quarkus的启动后首次响应时间大概提升了50倍左右(0.016vs0.943),这算是一个相当恐怖的数据了。

  • 上面的数据证明通过GraalVM编译后,启动及响应速度是大幅跃进了。那么内存使用呢,这个也是云原生比较关注的点。请看下图:

大概有个5倍左右的改进吧,应该说相当不错了。如果说前面的响应速度影响的还是用户体验,那8G内存的服务器跟40G内存的服务器,那省下来的可是真金白银啊。

聪明的小伙伴可能会说了,你上面的数据强是强,但是万物互联时代,主要看吞吐,对别的技术栈来说,上面的两个维度数据即使不理想,也不能算硬伤。吞吐强,才是真的强。我们一起来看下图:

来自TechEmpower的数据测试。我只截取了使用Javascript语言相关技术(都是后端哦)的成绩。先交代下背景,TechEmpower准备了同样的硬件环境,然后用不同的语言和框架来做同一件事情(提供后端HTTP API),并对它们进行压力测试记录下来成绩。所有参与测试的代码都是开源的,可以在GitHub上找到。当然这种“跑分”化的场景跟我们实际项目运行的情况肯定是千差万别的,TechEmpower考虑到实际情况的复杂性,准备了不同的测试场景,如图:



  • 其中Fortunes要从数据库取数然后在服务端进行数据排序,我觉得还是比较有代表性,所以上面的“跑分”截图就用的Fortunes的成绩。

  • 现在我们来具体看下成绩,TechEmpower的规则是以第一名的得分值作为基准,也就是100%。第一名es4x框架实际得分为237751,这个数字的含义截图中有提到——responses per second,也就是每秒响应数高达23万多,应该是个非常恐怖的数字了。我们可以对比看下nodejs的得分,也有91,799的每秒响应数,其实也很惊人,但是成绩也才有es4x的38.6%。如果你仔细看的话,会发现es4x的100%以及nodejs的38.6%数字后面还分别有两个百分比,这个数字代表其得分跟所有本次参与的技术及框架中最强者的比较。至于最强者是谁,我就卖个关子,有兴趣的朋友可以自己去官方网站查看。

  • 好了,现在你应该同意es4x是一个相当有性能优势的技术了。而es4x之所以能取得如此不俗的成绩,就是因为它用到了我们今天谈论的主角——GraalVM。

TechEmpower的GitHub上能看到说明,指出了这次测试是基于GraalVM的。略显遗憾的就是,TechEmpower并没有测试一版不依赖GraalVM的es4x,其实es4x是一种跑在JDK上的Javascript技术(如果你对JDK上跑Javascript感到惊奇,可以查看你不知道的Java),所以es4x跟GraalVM不是强关联的,只是es4x官方认为GraalVM性能更好,所以不论es4x的官网还是TechEmpower的跑分,都是把GraalVM作为了第一选择。

至此,我已经花了不少篇幅来介绍GraalVM的性能优势,相信你对它的性能水平有了一个大概的认识。前面的内容基本是拿来主义,重度依赖了互联网上已有的数据成果,下面我们开始第二个议题,真刀真枪的写点代码试一试。

多语言互相调用好使不


先来看看GraalVM支持哪些语言:

应该说有点意思,支持的语言还真不少。那我们就来动手试试吧。

安装GraalVM

我是通过sdkman来管理GraalVM的,建议你也这样做。

安装sdkman

curl -s "https://get.sdkman.io" | bash

使用sdkman查看可用的GraalVM

sdk list java

结果如图:

找一个最新版本安装,此处是20.3.0.r11-grl

sdk install java 20.3.0.r11-grl

这里提一句,执行完安装后,sdkman会询问你是否把刚安装的环境作为默认环境,我建议你选择否,这样就不会对你电脑之前安装好的Java、Node环境造成影响。当您想使用20.3.0.r11-grl的时候,只需要执行sdk use java 20.3.0.r11-grl,它只会影响当前终端上下文的环境。

基本的环境准备好后,你可以试试node --version,应该可以看到v12.18.4的输出,而如果你执行which node,应当会看到类似下面的内容:

有意思吧?GraalVM居然自带了一个node命令,一个不需要你安装https://nodejs.org就可以使用的node🤓。

安装完GraalVM,还需要安装多语言扩展包

js/node是一等公民,不需要特意安装,这个在上一节已经见识了😋

gu install python
gu install ruby
gu install r

经过漫长的等待,GraalVM及多语言环境就算安装完成,终于可以进入代码环节了。我们直接采用官方GitHub中的一个例子——polyglot-Javascript-java-r,一个演示了Javascript、R、Java混合使用的精彩demo。

你只需要准备两个文件就可以了,先来看看package.json,内容非常简单:

{
"dependencies": {
"express": "^4.16.3"
}
}

重头戏都在server.js,内容如下:

const express = require('express')
const app = express()
const BigInteger = Java.type('java.math.BigInteger')
app.get('/', function (req, res) {
var text = 'Hello World from Graal.js!
'
// Using Java standard library classes
text += BigInteger.valueOf(10).pow(100)
.add(BigInteger.valueOf(43)).toString() + '
'
// Using R methods to return arrays
text += Polyglot.eval('R',
'ifelse(1 > 2, "no", paste(1:42, c="|"))') + '
'
// Using R interoperability to create graphs
text += Polyglot.eval('R',
`svg();
require(lattice);
x <- 1:100
y <- sin(x/10)
z <- cos(x^1.3/(runif(1)*5&#43;10))
print(cloud(x~y*z, main&#61;"cloud plot"))
grDevices:::svg.off()
&#96;);
res.send(text)
})
app.listen(3000, function () {
console.log(&#39;Example app listening on port 3000!&#39;)
})

除了常规的node和express使用外&#xff0c;比较有意思的就是对Java和R的访问了。咱们一个个来看。

const BigInteger &#61; Java.type(&#39;java.math.BigInteger&#39;)使得我们直接在Javascript拿到了一个Java Class

后续就可以在Javascript无缝使用Java中的功能&#xff0c;比如静态方法valueOf、pow、add。一通操作后&#xff0c;我们获得了一个10的100次方的超大整数&#xff0c;并让其和43相加。

Polyglot.eval(&#39;R&#39;,&#39;ifelse(1 > 2, "no", paste(1:42, c&#61;"|"))&#39;)演示了Javascript中通过Polyglot.eval动态执行其他语言表达式。这里显然是执行了一个R的表达式。其他语言都是支持的&#xff0c;比如python你可以使用这样的代码var array &#61; Polyglot.eval("python", "[1,2,42,4]")&#xff0c;就可以获得一个在python中制造的数组了。

另一段比较长的Polyglot.eval就是本次demo的核心了&#xff0c; 其实也是R语言的专属技能。关于R语言的使用&#xff0c;已经超出了本文的讨论范围&#xff0c;有兴趣的小伙伴可以查看官方文档。


让我们来看看结果吧&#xff0c;先执行npm install把依赖安装好&#xff0c;然后你要用GraalVM的node命令启动项目&#xff0c;请一定注意&#xff0c;不是用你曾经熟悉的那个node哦。执行node --jvm --polyglot server.js&#xff0c;然后你会看到如下输出&#xff1a;

赶紧打开浏览器访问一下http://127.0.0.1:3000看看效果吧&#xff1a;


非常精彩&#xff0c;你不费吹灰之力就在html中构建了一个基于svg的三维坐标系&#xff0c;仿佛开启了在html展示数学技艺的大门——当然&#xff0c;如果你想进门转转的话&#xff0c;还得回头恶补一下数学和R语言&#xff0c;至少我是这么打算的&#x1f609;。

现在你理解多语言的程序环境是一件多么激动人心事了吧。这里没有口水战&#xff0c;有的只是百家争鸣&#xff0c;取长补短&#xff0c;共建繁荣。所以我才说Oracle的野心真的很大&#xff0c;通过GraalVM拿出一个多语言支持的环境&#xff0c;并且性能还更强&#xff0c;还可以预编译成二进制文件&#xff0c;直接分发高效运行。如果真有这样的东西&#xff0c;谁不喜欢呢。

三、编译二进制香不香
下面终于到最后一个环节了&#xff0c;把程序打包成二进制程序。按照官网的指点&#xff0c;首先我们要安装native-image来解锁编译二进制文件的技能。你需要执行:

gu install native-image
安装完native-image后&#xff0c;当我满心欢喜的执行native-image --language:js server.js试图把上面演示的server.js编译成二进制的时候&#xff0c;居然报错了&#xff1a;

去官网查阅了native-image的文档才知道&#xff0c;native-image只支持JVM-based的语言&#xff0c;比如Java、Scala、Clojure、Kotlin这些JVM的亲缘语言。

没办法&#xff0c;那我们还是拿Java开刀吧&#xff0c;这里我准备了一个简单的Java类&#xff1a;

import org.graalvm.polyglot.*;
public class PolyglotJavaJS {
public static void main(String[] args) {
Context polyglot &#61; Context.create();
Value array &#61; polyglot.eval("js", "eval(&#39;1&#43;1&#39;)");
int result &#61; array.asInt();
System.out.println(result);
}
}

可以看到中间我用GraalVM提供的工具执行了一小段Javascript脚本&#xff0c;通过Javascript中的eval函数计算了1&#43;1。eval这种开挂的函数在Javascript这种动态语言里挺常见的&#xff0c;但是在Java这种静态语言就特别少见&#xff0c;也制约了好多编程场景&#xff0c;我个人感觉GraalVM能通过这种非主流的方式给Java带来eval的特性还挺香的。下面我们来把这个Class打包成二进制文件&#xff1a;


  • 第一步&#xff0c;编译.java为.class&#xff1a;

javac PolyglotJavaJS.java

  • 第二步&#xff0c;有了.class文件后我们可以验证一下代码&#xff1a;

Java PolyglotJavaJS

这时控制台打印了2&#xff0c;看起来一切正常。

  • 第三步&#xff0c;用native-image把.class编译可执行文件&#xff08;也就是二进制文件&#xff09;。

native-image --language:js PolyglotJavaJS

由于代码里我们用到了Javascript相关内容&#xff0c;所以编译的时候需要提供参数–language:js。

经过一个漫长的等待&#xff08;我这边是3分多钟&#xff09;&#xff0c;还有恐怖的内存消耗&#xff08;被native-image进程消耗掉了6个多G&#xff09;&#xff0c;我们终于得到了如图的执行结果&#xff1a;

当然还有我们想要的可执行文件polyglotjavaJS&#xff0c;一个惊人的97M的文件。

好在这个文件执行起来还不赖&#xff0c;直接运行./polyglotjavajs就可以看到我们想要的结果了。如果在执行的命令前面加上time&#xff0c;我们就能和JVM解释执行的版本做个对比了&#xff1a;

可以看到&#xff0c;二进制版本确实有着更快的执行速度和更低的CPU使用率&#xff0c;跟JVM版本对比优势还是比较明显的。就是97M的文件大小&#xff0c;我觉得有点大了&#xff0c;不利于分发。下面尝试把Javascript的相关内容移除&#xff0c;只实现最简单的逻辑&#xff1a;

public class PolyglotJavaJS {
public static void main(String[] args) {
System.out.println("Hello GraalVM!");
}
}

然后我们再次执行javac和native-image PolyglotJavaJS&#xff0c;又得到了一组新的编译日志&#xff1a;

可喜可贺&#xff0c;编译过程对内存和时间的消耗都只有之前的三分之一。再来看下编译后的文件大小&#xff1a;

只有7.7M了&#xff0c;瞬间觉得香了&#xff0c;有木有。同样的&#xff0c;我们再把二进制和JVM版的执行速度对比一下&#xff1a;

二进制版本依然保持了不俗的优势。

这么看来GraalVM打包二进制可执行文件的功能&#xff0c;在JVM系语言上还是有一定优势的。除了打包过程中耗时比较长以及对机器的CPU、内存有不小的占用&#xff0c;二进制程序执行速度还是挺快的&#xff0c;明显感觉比解释型执行的语言要快。打包出来的文件Size&#xff0c;确实不小&#xff0c;与主流的硬编译语言C、C&#43;&#43;、Go、Rust比差太远了&#xff0c;我随便测试了一个Rust的Hello World程序&#xff0c;编译后的可执行文件才370K。这方面的差距&#xff0c;我觉得在很长一段时间GraalVM是不可能追赶上了。好在5G时代带宽可能不是个大问题&#xff0c;磁盘也越来越白菜价了&#xff0c;可执行文件的大小应该不是我们要考量的主要因素。

总结

GraalVM在整个JVM领域无疑是个异类&#xff0c;有众多激进的特性。并且由Oracle做背书&#xff0c;同时提供社区版和商业版&#xff0c;可持续性不需担心&#xff0c;未来的发展肯定是要越来越好的。但是Java作为一个有年代感的语言&#xff0c;早也不复舞台C位的荣光。最近几年JVM系的好东西涌现了不少&#xff0c;无奈国内接受度真的不高&#xff0c;这可能是我辈JVM系程序员最尴尬的境地了。






推荐阅读
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • python之poc编写——sql篇
    文章目录sql注入漏洞漏扫单个网站基础sql扫描多个网站sql基础扫描时间盲注型扫描升阶版sq ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • Jquery 跨域问题
    为什么80%的码农都做不了架构师?JQuery1.2后getJSON方法支持跨域读取json数据,原理是利用一个叫做jsonp的概念。当然 ... [详细]
  • PHP中的curl_multi系列函数可以实现同时请求多个URL来实现并发,而不是像普通curl函数那样请求后会阻塞,直到结果返回才进行下一个请求。因此在批量请求URL时可通过curl_multi系列函数提升程序的运行效率。curl普通请求$startT ... [详细]
  • ZABBIX 3.0 配置监控NGINX性能【OK】
    1.在agent端查看配置:nginx-V查看编辑时是否加入状态监控模块:--with-http_stub_status_module--with-http_gzip_stat ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了markdown[软件代理设置]相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 进入配置文件目录:[rootlinuxidcresin-4.0.]#cdusrlocalresinconf查看都有哪些配置文件:[rootlinuxid ... [详细]
  • php7 curl_init(),php7.3curl_init获取301、302跳转后的数据
    最近在做一个蜘蛛项目,发现在抓取数据时,有时会碰到301的页面,原本写的curl_init函数php7-远程获取api接口或网页内容&#x ... [详细]
  • OrbitDBPeer 2 Peer Database using CRDTs
    2019独角兽企业重金招聘Python工程师标准Apeer-to-peerdatabaseforthedecentralizedwebOrbitDBisaserverless ... [详细]
  • 为PHP5安装curl和gd
    2019独角兽企业重金招聘Python工程师标准一、查看php5是否安装了curl:1在web服务器目录(Ubuntu下通常为varwww ... [详细]
  • Istio是一个用来连接、管理和保护微服务的开放平台。Istio提供一种简单的方式来为已部署的服务建 ... [详细]
author-avatar
墨镜DHED_304
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有