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

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

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

Peter Nagy 和我在Oracle Groundbreakers Tour 2020 LATAM 上发表了一篇题为“Go Java,Go!”的论文。我们问自己一个问题“Java 微服务能和 Go 一样快吗?” 我们创建了一些微服务并进行了一些基准测试,并在该活动中展示了我们的结果。但还有更多需要探索,所以我们决定将我们的演示文稿变成这篇文章。随着我们进行更多的测试和开发,我们计划跟进更多的帖子。

前提

我们想尝试看看 Java 微服务是否可以像 Go 微服务一样运行得那么快。普遍的行业信念似乎是 Java“陈旧”、“缓慢”和“乏味”;Go 是“快速”、“新”和“酷”的。但我们想知道这些特征是否得到实际性能数据的保证或支持。

我们想要一个公平的测试,所以我们创建了一个非常简单的微服务,没有外部依赖(例如数据库),并且代码路径非常短(只是操作字符串)。我们确实包括了指标和日志记录,因为这些似乎总是包含在任何真正的微服务中。我们使用了小型轻量级框架(Helidon for Java 和 Go-Kit for Go),我们还试验了用于 Java 的纯 JAX-RS。我们试验了不同版本的 Java 和不同的 JVM。我们对堆大小和垃圾收集器进行了一些基本调整。我们在测试运行之前预热了微服务。

一点历史——Java

Java 由被 Oracle 收购的 Sun Microsystems 开发。它的 1.0 版本是在 1996 年发布的,最新版本是 2020 年的 Java 15。主要设计目标是 Java 虚拟机和字节码的可移植性,以及带垃圾回收的内存管理。它仍然是最流行的语言之一(根据StackOverflow和TIOBE等来源),它是在开源中开发的。

让我们谈谈“Java 的问题”。它以速度慢而著称,这可能不再合理,但更具历史意义。它确实有一些性能敏感的区域,包括存储对象数据的堆;管理堆的垃圾收集器;和即时 (JIT) 编译器。

多年来,Java 有许多不同的垃圾收集算法,包括串行、并行、并发标记/清除、G1 和新的 ZGC 垃圾收集器。现代垃圾收集器旨在最小化垃圾收集“停止世界”暂停的持续时间。

Oracle 实验室开发了一种名为GraalVM的新 Java 虚拟机,它是用 Java 编写的,具有新的编译器和一些令人兴奋的新功能,例如能够将 Java 字节代码转换为无需 Java VM 即可运行的本机映像。

一点历史——Go

Go 由谷歌的 Robert Griesemer、Rob Pike 和 Ken Thomson 创建。他们共同为 UNIX、B、C、Plan9、UNIX 窗口系统等做出了重大贡献。)它是开源的,于 2012 年发布了 1.0 版,并于 2020 年发布了 1.15 版。它在两个方面都在快速增长采用以及语言和工具生态系统本身。

Go 受到 C、Python、Javascript 和 C++ 的影响。它旨在成为高性能网络和多处理的最佳语言。

当我们进行这次演讲时,StackOverflow 有 27,872 个问题被标记为“Go”,而 Java 有 1,702,730 个问题。

Go 是一种静态类型的编译语言。它的语法类似于 C。它具有内存安全、垃圾收集、结构类型和 CSP 风格的并发性(通信顺序进程)。它有称为 goroutines 的轻量级进程(这些不是 OS 线程),用于它们之间通信的通道(类型化,FIFO)。该语言不提供竞争条件保护。

Go 是许多 CNCF 项目的首选语言,例如 Kubernetes、Istio、Prometheus 和 Grafana 都是(大部分)用 Go 编写的。

它旨在具有快速构建时间和快速执行。它是固执己见的——不再争论两个或四个空格!

Go 有什么好处(与 Java 相比)——这是我根据我的经验得出的个人意见:

  • 更容易实现函数模式,如组合、纯函数、不可变状态。

  • 样板代码少得多(但仍然太多)。

  • 它仍处于生命周期的早期,因此它没有向后兼容性的沉重负担——他们仍然可以通过破坏来改进它。

  • 它编译成一个本地静态链接的二进制文件——没有虚拟机层——二进制文件包含运行程序所需的一切,这对于“从头开始”的容器来说非常有用。

  • 体积小,启动快,执行快。

  • 没有 OOP、继承、泛型、断言、指针算术。

  • 少括号,例如if x > 3 { whatever }

  • 强制执行没有循环依赖、没有未使用的变量或导入、没有隐式类型转换。

那么,Go 的“问题”是什么?同样,与 Java 相比,这是我个人的看法:

  • 工具生态系统不成熟,尤其是依赖管理——有多种选择,但没有一个是完美的,特别是对于非开源开发;现在有一个明显的“赢家”(Go 模块),但并不是每个人都采用它,因此仍然存在兼容性挑战。

  • 使用新的/更新的依赖项构建代码非常慢(就像 Maven 著名的“下载互联网”问题。

  • 导入将代码绑定到存储库,这使得移动代码成为一场噩梦。

  • IDE 适用于编程、文档查找、自动完成等;但是调试、分析等仍然具有挑战性。

  • 指针!我们以为我们在上个千年就把它们丢掉了!但至少没有指针运算。

  • 没有针对异常的 Java 风格的 try/catch(你最终写if err != nil得太频繁了),没有功能风格的基元,如列表、映射函数等。

  • 您通常最终会实现一些基本算法,因为它还不可用。最近我编写的代码通过两个字符串(列表)槽进行比较和转换。在函数式语言中,我可以使用内置函数map来做到这一点。

  • 没有动态链接!(“谁在乎?”你问)如果你想使用带有 GPL 这样“感染”静态链接代码的许可证的代码,这可能是一个真正的问题。

  • 调整执行或垃圾收集、分析执行或优化算法的旋钮并不多——Java 有数百个垃圾收集调整选项,Go 有一个——打开或关闭。

负载测试方法

我们使用 JMeter 来运行我们的负载测试。测试多次调用服务并收集有关响应时间、吞吐量(每秒事务数)和内存使用情况的数据。对于 Go,我们收集驻留集大小,对于 Java,我们跟踪本机内存。

在许多测试中,我们在与被测应用程序相同的机器上运行 JMeter。如果我们在不同的机器上运行 JMeter,结果似乎没有任何干扰或差异,因此这简化了设置。当我们稍后将应用程序部署到 Kubernetes 中时,JMeter 正在集群外部的远程机器上运行。

在测量之前,我们使用 1,000 次服务调用来预热应用程序。

应用程序本身的源代码和负载测试的定义都在这个 GitHub 存储库中:https ://github.com/markxnelson/go-java-go

第一轮测试

在第一轮中,我们在一台“小型”机器上运行测试,在本例中是一台 2.5GHz 双核英特尔酷睿 i7 笔记本电脑,配备 16GB 内存,运行 macOS。我们运行了 100 个线程,每个线程有 10,000 个循环,加速时间为 10 秒。Java 应用程序在 JDK 11 和 Helidon 2.0.1 上运行。使用 Go 1.13.3 编译的 Go 应用程序。

结果如下:

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

我们宣布 Go 成为第一轮的获胜者!

以下是我们对这些结果的观察:

  • 日志记录似乎是一个主要的性能损失,尤其是 java.util.logging。因此,我们在有和没有日志记录的情况下运行了测试。我们还注意到,日志记录是影响 Go 应用程序性能的一个重要因素。

  • Java 版本占用的内存明显更大,即使是对于如此小而简单的应用程序也是如此

  • Warmup对 JVM 有很大的影响——我们知道 JVM 在运行时会进行优化,所以这是有道理的

  • 我们在此测试中比较了不同的执行模型——Go 应用程序被编译成本机可执行的二进制文件,而 Java 应用程序被编译成字节码,然后在虚拟机上运行。我们决定引入 GraalVM 原生镜像,使 Java 应用程序的执行环境更接近 Go 应用程序的环境。

推荐书单

《项目驱动零起点学Java》

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

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

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

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

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

 

精彩回顾

部署Spring Boot应用程序

Java Spring Boot 3.0.0 RC1 震撼登场!

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值