GraalVM是一个通用的虚拟机,用于运行应用程序,如JavaScript、Python、Ruby、R、JVM等语言,如java、Scala、Groovy、Kotlin、Crojule和基于LLVM的语言,如C++和C++。
对我来说,最有趣的特性之一是编译为基于JVM的应用程序的本机二进制(在GraalVM中通常称为本机映像)。本机映像意味着编译将是独立的,不需要JVM(如C、C++或Golang),但它具有权衡(JIT vs AOT)和限制。
Spring框架,JVM世界中最成熟和最流行的框架之一,2019年中,SpringGraalVM特性被开发用于支持SpringBoot的本机映像编译(SpringFramework 5.2),但它需要巨大的内存构建过程,这个提交使得内存使用量更小。
一些新的Java框架已经具备了现成的本机图像编译功能,比如Quarkus、Micronaut和Helidon。几个月前我有兴趣尝试Quarkus,实际上1.0是去年11月发布的,但是我没有太多的空闲时间来尝试。几个月前,在尝试了几天的Quarkus之后,我很好奇用Spring(SpingGraal native)对Quarkus进行基准测试。
几周前,SpringGraalNative0.7.1已经发布,很多问题已经解决,我在GCP上有免费的学分,所以,让我们再试一次,做一些基准测试。我知道现在比较springgraalvm native是不公平的,也许我们可以说这是一个“实验报告”。
应用
该基准测试针对四种类型的应用程序
- 带WebMVC的SpringBoot
- 带Webflux的
- SpringBoot
- Quarkus
- 带Spring API扩展的Quarkus
所有这些都只是简单的CRUD应用程序通过http和PostgreSQL数据库。有6个http端点
- 插入
- 按id查找
- 按页查找
- 按特定列查找(筛选)
- 更新
- 删除。
Webflux版本中的Spring数据和JDBC版本不是被动的。我添加Webflux版本只是为了比较,因为Quarkus是基于Netty的。
有关如何将应用程序编译为本机映像,您可以查看Quarkus的此文档和spring graalvm本机的此文档。我对springgraalvm本机和自定义构建脚本使用混合模式。
对于框架和运行时版本,我使用springboot2.3.1(springgraalvm native 0.7.1)、quarkus1.5.2、graalvm2.1.0java11。
构建过程
构建过程是在4个CPU、16 GiB RAM虚拟机上完成的,空闲时RAM使用率为2.8%。
1. 构建时间
- spring-boot8分39秒
- spring-boot-webflux 8分12秒
- quarkus3分55秒
- quarkus spring api 3分57秒
在我多次尝试编译之后,构建时间的不一致性可能会达到20-30秒。
2. CPU使用率(%)随时间变化
3. 内存使用率(%)
4. 峰值RAM使用率
- spring-boot10.1 GiB
- spring-bootwebflux 9.8 GiB
- quarkus8 GiB
- quarkus spring api 8 GiB
5. 二进制大小
- spring-boot196.6 MB
- spring-boot webflux 182.7 MB
- quarkus69.8 MB
- quarkus spring api 69.6 MB
好吧,Spring的构建时间和二进制大小的结果要高得多,让我们等待spring5.3和springgraalvm native的非实验版本。
启动时间
所有的应用程序都是在1s下在2个CPU或1个CPU上启动的。
压力测试
虚拟机规范化
数据库:6 VCPU,16 GiB RAM,SSD(us-west1-b)
应用:1 VCPU,2 GiB RAM(us-west1-b)
JMeter:4 VCPU,16 GiB RAM(us-west2-a)
JMeter VM位于不同的区域,因为我使用了免费试用帐户,每个区域有8个vcpu限制。
脚本
我使用JMeter随机控制器随机请求所有端点15分钟。在此之前,我截断表并插入10000条记录。
我没有对所有的应用程序做特别的调整或其他什么,所有的默认值(包括springwebmvc,所以,200个tomcat线程),只是设置了连接池的数量。我只在VM级别做了一些调整,增加了打开文件的最大数量,并启用了tcp_tw_reuse
。
吞吐量结果
在运行15分钟测试之前,我尝试了几个60秒的测试,以找到这种VM规范最合适的设置(JMeter线程(并发用户)和连接池数量)。我使用Quarkus作为基线,这是结果。
基于这个结果,我认为150个JMeter线程足够大了。为了提高效率,让我们只使用池中的2个连接和1vCPU。
这是池中2个连接在15分钟内处理150jmeter线程的结果。
- spring-boot 390.1/s
- spring-boot webflux 631.6/s
- quarkus 1042.7/s
- quarkus spring api 871.1/s
这是一段时间内(每30秒)的平均吞吐量。
资源利用(压力测试期间)
应用程序虚拟机
CPU使用率(%)随时间变化
注意:quarkus spring api和所有spring版本的应用程序VM CPU使用率随着时间的推移而减少。但在dbvm上,该版本的CPU使用率正在增加。
随时间推移的RAM使用率(%)
数据库虚拟机
CPU使用率(%)随时间变化
注意:quarkus spring api和所有spring版本的数据库VM CPU使用率随着时间的推移而增加。我还没有进一步调查。可能是因为我在查找JMeter线程数时使用了Quarkus版本作为基线,而另一个无法使用该设置处理请求。
CPU使用率(%)随时间变化
完整代码地址:https://github.com/ard333/native-binaries-benchmark
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1868.html
暂无评论