Java曾经著名的格言:“编写一次,随处运行”在今天已经过时了,我们唯一想运行代码的地方就是在容器内。“及时”编译器没有任何意义。出于这个原因,Java生态系统可能正在转型以更好地适应云。Oracle的GraalVm允许将字节码编译为Linux可执行文件(ELF),而RadHeat的Quarkus和其他框架使其像引导React应用程序一样简单。Quarkus还使用Netty和Vertx.x作为核心来构建非常高效的响应式Web服务。>quarkus官方性能统计Java编译为可执行二进制文件,启动时间为毫秒,内存占用量小。这可以利用Java生态系统,甚至可以用Scala和Kotlin等其他JVM语言编写!听起来好得令人难以置信......如果你不相信,你可以使用在线项目生成器或使用maven插件项目在本地生成它来玩Quarkus。而Golang则生于云端,在容器中运行没有任何负担。它被认为是云的编程语言。小型二进制文件、快速启动程序、小内存占用将从第一天开始就可以解决问题。并被广泛采用。对Java世界的严峻挑战。Java有机会吗?只有时间会给出答案。但是,出于好奇,我想在性能和开发体验方面将Java云原生服务与golang对应的服务进行比较。在本文中,我将重点介绍两项服务。比较它们的CPU、RAM、延迟和正常运行时间。这些服务将在具有相同资源分配的容器中启动,Apache基准测试将使它们大汗淋漓。对于我的案例研究来说,这是一个“足够好”的基准测试,因为我不想找到最好/最差的基准测试结果,而是比较在同一环境中执行的两个基准测试。场景两种服务都将连接到在另一个容器中运行的MySQL数据库,该容器具有一个表和三个行。>数据库每个服务将获取所有三行,将它们转换为域对象,然后写入一个JSON数组响应。Apache基准将运行10K请求,并发级别为100,是quarkusJVM版本的两倍(也用于测试“冷”/“热”JVM))>apache基准命令Golang服务使用流行的响应称为gin具有出色基准的Web框架。我在寻找golang的非阻塞MySQL驱动程序时一无所获,互联网上也建议使用go-sql-driver,这就是我要使用的。golang风格非常明确。一种态度在你的脸上。主要功能启动服务器,配置请求处理程序,并打开数据库连接。构建本机go可执行文件>简单快速的构建过程。我必须使用的唯一工具是go编译器。一点也不喧嚣。KotlinCloudNativeServices—Quarkus这是一个大致遵循quarkusreactiveMySqlExtendedGuide的Kotlin示例。>数据源配置与go版本相比,有一些隐式的东西,CDI依赖注入,带有javax注释的声明式路由,自动配置解析和数据源/连接创建/服务器引导。但这就是使用框架的代价,它会为您完成繁重的工作并决定其工作方式。但是,它比go版本短得多,只要我不介意黑魔法!在引擎盖下有一个由Vert.x多事件循环包裹的Netty反应式Web服务器,可以通过线程访问Vert.x反应式MySQL驱动程序处理多个数据库连接。此外,我可以使用Kotlin令人惊叹的集合库折叠列表,其中go版本还没有泛型(但即将推出),也没有我必须手动编写或生成的丰富的标准集合库。构建Java本机可执行文件>花了4分钟,部分原因是Gradle在LinuxGraa中执行本机映像编译基本上,我能够弄清楚构建本机可执行文件的容器是SubstrateVM。设计用于提前编译的嵌入式虚拟机链接到我们的代码并作为一个单元编译。Oracle说这很了不起,但并非没有代价,SubstrateVM的优化比HotSpotVm少,并且有一个更简单的垃圾收集器。执行此操作的编译器称为“Graal”,它与语言无关,在使用Java字节码之前,需要将其翻译成中间表示形式,即Truffle语言。这非常有趣,可以在这篇文章中找到对Graal和Truffle的很好解释。构建Java本机映像似乎更复杂、更慢,并且生成的二进制文件数量几乎是原来的两倍。但它有效!与JavaUber(胖)Jar相比,一个35M的可执行二进制文件实际上是什么,它很容易大十倍。35MB甚至可以放入awslambda。强调服务我在我的本地机器上使用以下设置运行所有测试:未使用:MacBookPro(15英寸,2017年)2.9GHzIntelCorei7(8核)16GB2133MHzLPDDR3未使用工具调用cAdvisor来监视我容器的状态。场景quarkusjvm热点容器quarkusjavanative容器golang容器每个分配以下资源100MB/0.5CPU|200MB/1个CPU|300MB/2CPU我感兴趣的是cpu/ram利用率(多核利用率)cpu/ram峰值cpu/ram空闲启动时间响应延迟平均/最大吞吐量(每秒请求数)现在我将运行许多基准测试并收集每个基准的许多数据点。如果信息太多,请随意跳到摘要githubrepo的末尾,这个实验的所有代码都可以在这里找到quarkusjvmhotspot—100MB/0.5CPUidlecpuusage0.25%idleramusage66MBboottime6s>CPU引导过程中的使用。(一个尖峰,可能是jit+launchingJVM)第一轮压力测试(ColdJVM)令人惊讶的是,没有失败的请求。>压力期间的CPU使用率。>RAM从60MB启动到近100MB(限制)并保持在那里。第2轮压力测试(热JVM)quarkusjvmhotspot—200MB/1CPU空闲CPU使用率0.13%空闲ram使用情况Case66MB启动时间3s>引导期间的CPU使用率。(再次尖峰)第一轮压力测试(冷JVM)>压力下的CPU/RAM使用>令人惊讶的是,JVM没有吃掉所有分配的200MB,而140MB就足够了第二轮压力测试(热JVM)quarkusjvm热点—300MB/2CPUidlecpu/ramsameaspreviousschemeboottime1.1s(NICE)>CPUusageduringbootstrap,又是一个峰值。第一轮压力测试(冷JVM)>良好的CPU利用率>142mb内存就足够了第二轮压力测试(热JVM)现在,让我们看看本地映像的性能如何。quarkusJavaNative—100MB/0.5CPU启动时间:0.125秒。(!!!)启动时没有CPU峰值>引导程序压力测试结果期间的cpu/ram>CPU达到预期的0.5限制>良好的ram使用,19MB活动内存。WOWquarkusJavaNative—200MB/1CPUInstantBoot(0.0125s)在压力下使用4个空闲ram使用率19种内存100%CPU使用率启动时没有CPU峰值测试结果quarkusJavaNative—300MB/2CPU没有提升。golang—100MB/0.5CPU空闲CPU0空闲内存2.3MB(不错)启动时间:几分之一秒启动时没有CPU峰值结果有点偏差。出于某种原因,一小部分请求大约需要7秒才能完成。当试图再次运行测试以查看偏斜的结果是否重现测试时,它实际上被压垮了!运行时错误:无效的内存地址或nil指针取消引用。嗯...也许我做错了什么?似乎go-sql库中存在错误。正如文档所说,从表中读取的代码是100%并且在99%的时间内有效。这不应该发生。golang--200MB/1CPU我一直收到运行时错误。可疑总是在测试结束时。不过go-mysql驱动的修正不是主要问题,所以在90%的请求完成后手动终止测试。压力下的CPU/RAM使用率>压力下的CPU使用率>压力下的RAM使用率。12.27MB,非常好。golang—300MB/2个CPU没有明显改进,所有统计数据几乎相同。CPU利用率低于1.0。我不知道为什么go没有充分利用更多的内核,有趣的是......可能是因为该过程是IO绑定的,或者可能需要手动配置gin以更好地利用多个内核。Summary>aggregatedstats(warmjvm/nativeimage|golang)似乎Quarkus已经准备好生产,它允许简单的JVM/nativerelease/dev模式,并允许在本地运行本机测试。另外,只要不使用反射或JNI,就可以安全地配置GraalVM。否则,您将不得不自己配置graal编译器,对此也有现有的解决方案。延迟和吞吐量golang和云原生Java产生了相似的结果,尽管平均而言golang服务略有优势。但是,javanative结果更稳定。Golang服务有时会在1.25μs内响应,很少会在7s内响应。“预热”的JVM产生了良好的结果,但比本机或go版本差。CPU利用率go和native-java在少于单核的情况下在负载下表现不佳,并且在使用2核启动时它们没有显示出显着的改善。可能是因为工作负载受IO限制。或者因为gin/Netty的默认配置没有考虑多核。另一方面,JVM利用所有提供给它的核心并以各种方式提高性能。RAM使用压力很大,java本机40MB,golang服务24MB。两种情况都很好,尽管golang版本使用的ram几乎减少了两倍。JVM在压力下使用了140MB。完全官方的quarkus统计数据。对于JVM来说还不错,但比golang版本快了将近6倍。启动时间golang和云原生Java都立即启动,而JVM版本需要几秒钟(取决于分配的CPU)并在启动时产生CPU峰值。开发经验这与其说是一个实际问题,不如说是一个宗教问题。生病了,请谨慎回答。Quarkus创建了Java世界中非常熟悉的抽象(例如基于注解的DI)。它启动服务并为您创建连接池。可以使用丰富的标准库和泛型集合。然而,感觉有点像黑魔法,一旦它不起作用,你会感到无助。此外,将Java代码编译为本机二进制文件并不简单,您必须了解限制和注意事项,虽然RedHat在扩展方面取得了长足进步,但并非每个Java库都可以与本机编译兼容。.(预配置为本地编译的Java库)。使用与本机编译不兼容的库(例如Guice)将需要您手动配置GraalVM。这是可能的,但不像使用jar那样简单。Quarkus和GraalVM也“相对”较新。因此,许多冒险等待着。但由于它是双模式(JVM或本机)。万一本机版本停止工作,总是有回退,这是解决任何新出现问题的好方法。另一方面,Golang直到现在(存在10年后)才承认需要泛型。当然,它不喜欢隐藏事件的继续。在许多方面,这是一件好事。此外,虽然go社区确实在迎头赶上,但可用的工具和库却很少(例如,只有一个流行的阻塞MySQL驱动程序)。另一方面,它的编译和构建过程非常快速/简单。每个golang包都将为您工作,而不受Java本机平台引入的限制。结论Java成为云原生是很棒的,Golang不会像JVM那样过度。我相信它会在未来得到广泛应用。但是golang绝对可以打。所以慎重选择!别忘了给仙人掌浇水
