Java微服务和Go语言大比拼(下)

Java微服务能和 Go一样快吗?

微信搜索关注《Java学研大本营》,加入读者群,分享更多精彩

GraalVM 原生镜像

GraalVM 具有本机映像功能,允许您获取 Java 应用程序并将其编译为本机可执行代码。来自 GraalVM 网站:

此可执行文件包括应用程序类、来自其依赖项的类、运行时库类以及来自 JDK 的静态链接本机代码。它不运行在 Java VM 上,但包含来自不同运行时系统的必要组件,如内存管理、线程调度等,称为“Substrate VM”。Substrate VM 是运行时组件(如反优化器、垃圾收集器、线程调度等)的名称。

这是添加了 GraalVM 本机图像测试的第一轮结果(使用 GraalVM EE 20.1.1 — JDK 11 构建的本机图像):

Application Logging Warmup Avg. Response Time (ms) Transactions / sec Memory (RSS) (Start/End)
Golang Yes No 5.79 15330.60 5160KB / 15188KB
Golang No No 4.18 20364.11 5164KB / 15144KB
Golang No Yes 3.97 21333.33 10120KB / 15216KB
Java (Helidon) Yes No 12.13 8168.15 296376KB / 427064KB; committed = 169629KB +15976KB (NMT); reserved=1445329KB +5148KB (NMT)
Java (Helidon) No No 5.13 17332.82 282228KB / 430264KB; reserved=1444264KB +6280KB; committed=166632KB +15884KB
Java (Helidon) No Yes 4.84 18273.18 401228KB / 444556KB
Native Image Yes No 12.01 7748.27 18256KB / 347204KB
Native Image No No 5.59 15753.24 169765KB / 347100KB
Native Image No Yes 5.22 17837.19 127436KB / 347132KB

在这种情况下,与在 JVM 上运行应用程序相比,我们没有看到使用 GraalVM 本机映像对吞吐量或响应时间有任何实质性改进,但内存占用量更小。

以下是一些测试的响应时间图:

第一轮的响应时间图 请注意,在所有三个 Java 变体中,第一个请求的响应时间要长得多(寻找与左轴正对的那条蓝线)。在所有情况下,我们还看到了一些峰值,我们假设这是由垃圾收集或优化引起的。

第二轮

接下来我们决定在更大的机器上运行测试。对于这一轮,我们使用了一台具有 36 个内核(每个内核两个线程)、256GB RAM、运行 Oracle Linux 7.8 的机器。

与第一轮一样,我们使用了 100 个线程,每个线程 10,000 个循环,10 秒的加速时间和相同版本的 Go、Java、Helidon 和 GraalVM。

以下是结果:

Application Logging Warmup Avg. Response Time (ms) Transactions / sec Memory (RSS) (Start/End)
Native Image Yes No 5.61 14273.48 28256KB / 1508600KB
Native Image No No 0.25 82047.92 29368KB / 1506428KB
Native Image No Yes 0.25 82426.64 1293216KB / 1502724KB
Golang Yes No 4.72 18540.49 132334KB / 72433KB
Golang No No 1.69 37949.22 12864KB / 70716KB
Golang No Yes 1.59 39227.99 16764KB / 76996KB
Java (Helidon) Yes No 7.38 11216.42 318545KB / 529848KB
Java (Helidon) No No 0.40 74827.90 307672KB / 489568KB
Java (Helidon) No Yes 0.38 76306.75 398156KB / 480460KB

我们宣布 GraalVM 原生镜像成为第二轮的赢家!

以下是这些测试的响应时间图:

启用日志记录但未预热的测试运行的响应时间

没有日志记录和预热的测试运行的响应时间

预热但没有记录的测试运行的响应时间

第二轮的一些观察:

  • Java 变体在此测试中表现得更好,并且在不使用日志记录时大大优于 Go

  • Java 似乎更能够使用硬件提供的多核和执行线程(与 Go 相比)——这在一定程度上是有道理的,因为 Go 旨在作为一种系统和网络编程语言,而且它是一种较年轻的语言,所以它是有理由假设 Java 有更多的时间来开发和调整优化

  • 有趣的是,Java 是在多核处理器还不普及的时候设计的,而 Go 是在多核处理器普及的时候设计的

  • 特别是,Java 日志记录似乎已成功卸载到其他线程/内核,并且对性能的影响要小得多

  • 这一轮的最佳性能来自 GraalVM 原生图像,平均响应时间为 0.25 毫秒,每秒处理 82,426 个事务,而 Go 的最佳结果为 1.59 毫秒和 39,227 tps,但这是以多两个数量级的内存为代价的用法!

  • GraalVM 本机图像变体比在 JVM 上运行的相同应用程序快 30-40%

  • Java 变体的响应时间似乎更加一致,但峰值更多——我们推测这意味着 Go 正在执行更多、更小的垃圾收集

第三轮——Kubernetes

在第三轮中,我们决定在 Kubernetes 集群中运行应用程序——您可能会说这是一个更自然的微服务运行时环境。

在这一轮中,我们使用了一个具有三个工作节点的 Kubernetes 1.16.8 集群,每个节点有两个内核(每个内核有两个执行线程)、14GB RAM 和 Oracle Linux 7.8。我们在一些测试中为每个变体运行一个 pod,在其他测试中运行一百个。

应用程序访问是通过 Traefik 入口控制器进行的,JMeter 在 Kubernetes 集群外部运行以进行一些测试,而对于其他测试,我们使用 ClusterIP 并在集群中运行 JMeter。

与之前的测试一样,我们使用了 100 个线程,每个线程 10,000 个循环和 10 秒的加速时间。

以下是每个变体的容器尺寸:

  • Go 11.6MB

  • Java/Helidon 1.41GB

  • Java/Helidon JLinked 150MB

  • 原生图像 25.2MB 以下是结果:

Pods Access Application Logging Avg. Response Time (ms) Transactions / sec
1 Traefik Golang No 5.07 14651.80
1 Traefik Native Image No 5.05 15812.28
1 Traefik Java (Helidon) No 7.05 11823.69
1 Traefik Java Jlink (Helidon) No 9.08 9271.02
100 Traefik Golang No 5.06 15646.75
100 Traefik Native Image No 5.17 15462.40
100 Traefik Java (Helidon) No 11.42 without warmup/ 5.07 with warmup 8015.96 / 15838.32
100 Traefik Java Jlink (Helidon) No 9.61 / 5.64 9424.62 / 14732.31
1 ClusterIP Golang No 1.2 43712.02
1 ClusterIP Native Image No 2.12 30497.10
1 ClusterIP Java (Helidon) No 7.19 / 5.73 12819.52 / 14878.95
1 ClusterIP Java Jlink (Helidon) No 7.19 / 6.27 12610.49 / 13817.68
100 ClusterIP Golang No 1.25 34170.51
100 ClusterIP Native Image No 1.32 33558.17
100 ClusterIP Java (Helidon) No 3.35 / 2.04 14358.94 / 24410.48
100 ClusterIP Java Jlink (Helidon) No 2.56 / 1.87 18098.23 / 26520.97

以下是一些响应时间图表:

Kubernetes 测试的响应时间 在这一轮中,我们观察到 Go 有时更快,而 GraalVM 原生图像有时更快,但这两者之间的差异很小(通常小于 5%)。

那么,我们学到了什么?

我们反思了所有这些测试和结果,以下是我们的一些结论:

  • Kubernetes 似乎并没有快速横向扩展

  • Java 似乎比 Go 更擅长使用所有可用的内核/线程——我们在 Java 测试中看到了更好的 CPU 利用率

  • Java 在具有更多内核和内存的机器上性能更好,Go 性能在更小/功能更弱的机器上更好

  • Go 的性能总体上稍微更一致——可能是由于 Java 的垃圾收集

  • 在“生产规模”的机器上,Java 很容易与 Go 一样快,或者更快

  • 日志记录似乎是我们在 Go 和 Java 中遇到的主要瓶颈

  • 现代版本的 Java 和像 Helidon 这样的新框架在消除/减少 Java 一些众所周知的长期存在的问题(例如冗长、GC 性能、启动时间等)的痛苦方面取得了长足的进步。

接下来是什么?

这是一个非常有趣的练习,我们打算继续努力,特别是:

  • 我们想用 Kubernetes 自动缩放做更多的工作——我们可能需要更复杂的微服务或更高的负载才能看到性能上的一些差异

  • 我们想研究更复杂的微服务、多个服务和熔断等模式,看看网络如何影响性能,以及如何调优微服务网络

  • 还想查看日志记录问题,看看可以做些什么来消除瓶颈

  • 我们想查看目标代码并比较正在执行的实际指令,看看我们是否可以在代码路径中做一些进一步的优化

  • 我们想知道 JMeter 是否可以产生足够的负载而不会成为瓶颈,但我们的测试表明这根本不是一个因素,它可以轻松地跟上 Go 和 Java 实现的步伐

  • 想对容器启动时间、内存占用等做更详细的测量。

随着我们进行更多实验并获得更多结果,我们将在此处发布它们!请继续关注,感谢阅读!

推荐书单

《项目驱动零起点学Java》

《项目驱动零起点学Java》共分 13 章,围绕 6 个项目和 258 个代码示例,分别介绍了走进Java 的世界、变量与数据类型、运算符、流程控制、方法、数组、面向对象、异常、常用类、集合、I/O流、多线程、网络编程相关内容。《项目驱动零起点学Java》总结了马士兵老师从事Java培训十余年来经受了市场检验的教研成果,通过6 个项目以及每章的示例和习题,可以帮助读者快速掌握Java 编程的语法以及算法实现。扫描每章提供的二维码可观看相应章节内容的视频讲解。

《项目驱动零起点学Java》贯穿6个完整项目,经过作者多年教学经验提炼而得,项目从小到大、从短到长,可以让读者在练习项目的过程中,快速掌握一系列知识点。

马士兵,马士兵教育创始人,毕业于清华大学,著名IT讲师,所讲课程广受欢迎,学生遍布全球大厂,擅长用简单的语言讲授复杂的问题,擅长项目驱动知识的综合学习。马士兵教育获得在线教育“名课堂”奖、“最受欢迎机构”奖。

赵珊珊,从事多年一线开发,曾为国税、地税税务系统工作。拥有7年一线教学经验,多年线上、线下教育的积累沉淀,培养学员数万名,讲解细致,脉络清晰。

《项目驱动零起点学Java》(马士兵,赵珊珊)【摘要 书评 试读】- 京东图书京东JD.COM图书频道为您提供《项目驱动零起点学Java》在线选购,本书作者:,出版社:清华大学出版社。买图书,到京东。网购图书,享受最低优惠折扣!https://item.jd.com/13607758.html

精彩回顾

部署Spring Boot应用程序

Java Spring Boot 3.0.0 RC1 震撼登场!

微信搜索关注《Java学研大本营》

访问【IT今日热榜】,发现每日技术热点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值