前言
Java 微服务能像 Go 微服务一样快吗?
这是我最近始终在考虑地一个问题。
去年 8 月份的 the Oracle Groundbreakers Tour 2020 LATAM 大会上,Mark Nelson 和 Peter Nagy 就对此做过一系列根底的的测试用以比拟。接下来就给大家介绍下。
在程序员圈子里,广泛的认识是 Java老、慢、无聊 ,而 Go 是 快、新、酷
为了尽可能的进行一个绝对偏心的测试,他们应用了一个非常简单的微服务,没有内部依赖关系(比方数据库),代码门路十分短(只是操纵字符串),应用了小型的、轻量级的框架(Helidon for Java 和 Go 工具包 for Go),试验了不同版本的 Java 和不同的 jvm。
对决双雄
咱们先来看下擂台两边的选手:
- 身穿深色战服的选手是JAVA
Java 是由被甲骨文收买的 Sun Microsystems 开发的。它的 1.0 版本是 1996 年公布的,最新的版本是 2020 年的 Java15。次要的设计指标是 Java 虚拟机和字节码的可移植性,以及带有垃圾收集的内存治理。它是全世界最风行的语言之一,在开源环境下开发。
咱们先看下 JAVA 的问题,大家普遍认为它最大的问题就是速度慢,曾经慢到让人感觉不再是正当的,而是更具历史意义的。不过这么多年来,Java 诞生了很多不同的垃圾收集算法用来放慢它运行的速度。
Oracle 实验室最近曾经开发了一个新的 Java 虚拟机 GraalVM,它有一个新的编译器和一些令人兴奋的新个性,比方可能将 Java 字节码转换成一个本机映像,能够在没有 javavm 的状况下运行等。
- 而它的对手就是年老充满活力的GO
GO 是由谷歌的罗伯特·格里默、罗伯·派克和肯·汤姆森创立的。他们对 UNIX、B、C、Plan9、UNIX 窗口零碎等做出了重大贡献。GO 是开源的,在 2012 年公布了 1.0 版本(比 JAVA 晚了 16 年),在 2020 年公布了 1.15 版本。无论是在采纳方面,还是在语言和工具生态系统自身方面,它都在快速增长。
GO 受 C、Python、JavaScript 和 C ++ 等多种语言的影响。被设计成高性能网络和多解决的最佳语言。
StackOverflow 有 27872 个带“Go”的问题,而 Java 只有 1702730 个。足见长江后浪推前浪。
Go 是一种动态类型的编译语言。它有称为 goroutines 的轻量级过程(这些不是 OS 线程),它们之间有独特的通信通道(类型化的,FIFO)。Go 是许多 CNCF 我的项目的首选语言,例如 Kubernetes、Istio、Prometheus 和 Grafana
赛前比照
从个人感觉来说,Go 相比 JAVA 来说,长处在于:
- Go 更容易实现复合、纯函数、不变状态等性能模式。
- Go 处于生命周期的晚期,因而它没有向后兼容性的沉重负担—Go 依然能够轻易突破某些限度来改良。
- Go 编译成一个本机动态链接的二进制文件 - 没有虚拟机层 - 二进制文件领有运行程序所需的所有,这对于“从头开始”的容器来说十分好。
- Go 体积小、启动快、执行快(目前是的)
- Go 没有 OOP,继承,泛型,断言,指针算法
- Go 写法上较少的括号
- Go 没有循环依赖、没有未应用的变量或导入、没有隐式类型转换的强制
- Go 样板代码少得多
毛病是:
- Go 工具生态系统还不成熟,尤其是依赖关系治理——有几个选项,没有一个是完满的,特地是对于非开源开发;依然存在兼容性挑战。
- 构建具备新的 / 更新的依赖项的代码十分慢(比方 Maven 驰名的“下载 Internet”问题)
- 导入将代码绑定到存储库,这使得在存储库中挪动代码成为一场噩梦。
- 调试、评测等依然是一个挑战
- 用到了指针
- 须要实现一些根本的算法
- 没有动静链接
- 没有太多旋钮来调优执行或垃圾收集、概要文件执行或优化算法。
较量开始
应用 JMeter 来运行负载测试。这些测试屡次调用这些服务,并收集无关响应工夫、吞吐量(每秒事务数)和内存应用状况的数据。对于 Go,收集驻留集大小;对于 Java,跟踪本机内存。
在测量之前,应用 1000 次服务调用对应用程序进行预热。
应用程序自身的源代码以及负载测试的定义都在这个 GitHub 存储库中:https://github.com/markxnelso…
第一回合
在第一轮测试中,在一台“小型”机器上进行了测试,是一台 2.5GHz 双核 Intel core i7 笔记本电脑,16GB 内存运行 macOS。测试运行了 100 个线程,每个线程有 10000 个循环,上升时间为 10 秒。Java 利用程序运行在 JDK11 和 Helidon2.0.1 上。应用 Go 1.13.3 编译的 Go 应用程序。
后果如下:
能够看出,第一回合是 Go 赢了!
JAVA 占的内存太多了;预热对 JVM 有很大的影响—咱们晓得 JVM 在运行时会进行优化,所以这是有意义的
在第一回合的根底上,意犹未尽的又引入 GraalVM 映像以使 Java 应用程序的执行环境更靠近于 Go 应用程序的环境,增加了 GraalVM 映像测试 (用 GraalVM EE 20.1.1 ー JDK 11 构建的本机映像) 的后果是:
通过应用 GraalVM 映像在 JVM 上运行应用程序,咱们没有看到吞吐量或响应工夫方面的任何实质性改良,然而内存占用确实变小了。
上面是一些测试的响应工夫图:
第二回合
在第二轮测试中,应用一台更大的机器上运行测试。36 核(每个核两个线程)、256GB 内存、运行 oraclelinux7.8 的机器。
和第一轮相似,应用了 100 个线程,每个线程应用了 10,000 个循环,10 秒的减速工夫,以及雷同版本的 Go,Java,Helidon 和 GraalVM。
后果如下:
这一回合是 GraalVM 映像赢了!
上面是一些测试的响应工夫图:
在这个测试中,Java 变体的体现要好得多,并且在没有应用 Java 日志记录的状况下,它的性能大大超过了 Go。Java 仿佛更能应用硬件提供的多核和执行线程(与 Go 相比)。
这一轮的最佳体现来自 GraalVM native image,均匀响应工夫为 0.25 毫秒,每秒事务数为 82426 个,而 Go 的最佳后果为 1.59 毫秒和 39227 个 tps,然而这是以多占用两个数量级的内存为代价的!
GraalVM 映像比在 jvm 上运行的同一应用程序快大概 30–40%!
第三回合
这次,较量在 Kubernetes 集群中运行这些应用程序,这是一个更天然的微服务运行时环境。
这次应用了一个 Kubernetes 1.16.8 集群,它有三个工作节点,每个节点有两个内核(每个内核有两个执行线程)、14GB 的 RAM 和 oraclelinux7.8。
应用程序拜访是通过 Traefik 入口控制器进行的,JMeter 在 Kubernetes 集群外运行,用于一些测试,而对于其余测试,应用 ClusterIP 并在集群中运行 JMeter。
与后面的测试一样,咱们应用了 100 个线程,每个线程应用了 10,000 个循环,以及 10 秒的减速工夫。
上面是各种不同容器的大小:
- Go 11.6MB 11.6 MB
- Java/Helidon 1.41GB 1.41 GB
- Java/Helidon JLinked 150MB 150mb
- Native image 25.2MB 25.2 MB
后果如下:
上面是一些测试的响应工夫图:
在这一轮中,咱们察看到 Go 有时更快,GraalVM 映像有时更快,但这两者之间的差异很小(通常小于 5%)。
Java 仿佛比 Go 更长于应用所有可用的内核 / 线程—咱们在 Java 测试中看到了更好的 CPU 利用率。Java 性能在领有更多内核和内存的机器上更好,Go 性能在较小 / 性能较弱的机器上更好。在一台“生产规模”的机器上,Java 很容易就和 Go 一样快,或者更快
最初
接下来会做更多的测试较量,来看一看到底谁更好!有趣味的你也能够本人试一试,记得通知咱们后果哦!
本文参考:https://medium.com/helidon/ca…
欢送关注我的公众号:程序猿 DD,取得独家整顿的收费学习资源助力你的 Java 学习之路!另每周赠书不停哦~