百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

云原生时代,Java还是Go

toyiye 2024-06-21 12:04 9 浏览 0 评论

Java曾经著名的座右铭:"一次编写,到处运行",已经很过时了,因为现在我们只想在容器里运行代码。在容器里,一个 "Just in time "的编译器意义不大。

出于这个原因,可能为了更好地适应云计算,Java生态系统正处于转型之中。Oracle 的GraalVm允许将字节码编译成Linux可执行文件(ELF),而Rad Heat的Quarkus以及其他框架,则立志让响应式服务这件事变得更简单。Quarkus以Netty和Vertx.x为核心,可以用来构建非常高效的响应式Web服务。

Java编译成可执行二进制文件,以毫秒级的速度启动,内存占用很小。这样就可以利用Java生态系统,甚至可以用其他JVM语言(如Scala和Kotlin)编写。你可以用online项目生成器玩玩Quarkus,或者用maven插件在本地生成一个项目。

而Golang则是为云而生的,在容器中运行时,没有遗留负担。它被认为是云端的编程语言。生成的二进制可执行文件很小,快速启动,内存占用也很小,而且这是从Go诞生之初就具备的特性。Golang的流行对 Java 世界形成了严峻的挑战。

Java有机会吗,也许只有时间才会告诉我们最终答案。然而,出于好奇,我想从性能和开发体验方面比较一下 Java 和 Golang 的云原生服务。

在这篇文章中,我将使用两种语言来写同样的服务。比较它们的CPU使用率、RAM、延迟和运行速度。这些服务将在容器中启动,资源分配相同,使用ab来测试。

对于我的案例来说,这是一个 "足够好 "的基准,因为我不假设找到最好/最差的基准结果,而是在同一环境下执行运行两个基准测试进行比较。

场景

这两个服务将连接到在另一个容器中运行的MySQL数据库,有一个表和三行数据。

每一个服务都会获取所有记录,将它们转化为对象,然后输出JSON数组。

ab将发出10K请求,并发级别为100,quarkus JVM版本运行两次(用于测试 "冷"/"暖 "JVM)。

Go语言版本

Go语言版本使用gin框架。

# the servicepackage main
import ( "database/sql" "fmt" "github.com/gin-gonic/gin" _ "github.com/go-sql-driver/mysql" "net/http")
type Fruit struct { Id int `json:"id"` Name string `json:"name"`}
var con *sql.DB
func init{ //opening a mysql connection pool with another container db, err := sql.Open("mysql", "root:password@tcp(host.docker.internal:3306)/payments") if err != nil { panic("failed to open a mysql connection") } con = db}
func main { r := gin.Default r.GET("/fruits", fruits) r.Run //server up on 8080}
// THE REQUEST HANDLERfunc fruits(c *gin.Context) { fruits := getFruits c.JSON(http.StatusOK, fruits)}
func getFruits Fruit { rows, _ := con.Query("SELECT * FROM fruits") fruits := Fruit{} for rows.Next { var r Fruit rows.Scan(&r.Id, &r.Name) fruits = append(fruits, r) } return fruits}

Golang的MySQL驱动的使用go-sql-driver。golang的代码风格是非常明确的。一种一切都在眼前态度。主函数启动服务器,配置请求处理程序,打开DB连接。

编译本地可执行文件

Kotlin版本

package org.acmeimport io.vertx.core.json.JsonArrayimport io.vertx.core.json.JsonObjectimport io.vertx.mutiny.mysqlclient.MySQLPoolimport io.vertx.mutiny.sqlclient.Rowimport io.vertx.mutiny.sqlclient.RowSetimport java.util.concurrent.CompletionStageimport javax.inject.Injectimport javax.ws.rs.GETimport javax.ws.rs.Pathimport javax.ws.rs.Producesimport javax.ws.rs.core.MediaType
@Path("/fruits")class FruitResource { @field:Inject lateinit var client: MySQLPool

@GET @Produces(MediaType.APPLICATION_JSON) fun listFruits: CompletionStage<JsonArray> { return client.query("SELECT * FROM fruits").execute .map { rows: RowSet<Row> -> rows.fold(JsonArray) { array, row -> array.add(JsonObject .put("id", row.getLong("id")) .put("name", row.getString("name"))) } }.subscribeAsCompletionStage }}
数据库连接使用Quarkus React Mysql 扩展。

与Go版本相比,代码有很大不同,比如CDI依赖注入,使用javax注释的声明式路由,自动配置解析,以及数据源/连接创建/服务器引导。这是使用框架的代价,它为你完成了繁重的工作,并决定了做事方式。不过,它比go版本代码要简短很多。

这里使用Netty响应式web服务器,由Vert.x多事件循环包装,还有一个Vert.x响应式MySQL驱动,这样可以用一个线程处理多个DB连接。

另外,我可以使用Kotlin的集合库的fold函数,这种函数还没有通用的Go版本。

编译Java版本的可执行文件

我已经弄清楚构建过程中发生了什么,其核心是SubstrateVM。它被设计在AOT过程中的可嵌入虚拟机,它会链接到我们的代码,并作为一个单元进行编译。然而根据Oracle的说法,SubstrateVM的优化比HotSpot Vm少,垃圾收集器也比较简单。

该AOT编译器被称为 "Graal",它是语言不相关的。java字节码需要被翻译成一种中间表示法(Truffle语言)。这在这篇文章【1】中可以找到关于Graal和Truffle的相关论述。

构建一个 Java 本地可执行文件看起来更复杂,编译得更慢,它产生的二进制文件几乎是Go版本两倍大小。然而一个35M的可执行二进制文件和Java FatJar相比,还是小D多了。35MB甚至可以让你使用aws lambda运行。

压力测试

我在本机运行所有测试,设置如下。

  • MacBook Pro(15英寸,2017年

  • 2.9 GHz英特尔酷睿i7(8个核心)。

  • 16 GB 2133 MHz LPDDR3

使用cAdvisor的工具来监控容器的统计数据。

场景

上述的每种情况都在以下三种配置上测试

  • 100MB / 0.5 CPU | 200MB / 1 CPU | 300MB / 2 CPU

我主要关注:

  • cpu/ram利用率(多核的利用率)

  • cpu/ram峰值

  • cpu/ram空余

  • 启动时间

  • 响应延迟avg/max

  • 吞吐量(每秒请求数)

测试结果

看起来Quarkus已经为生产环境做好准备了,它允许简单的JVM/原生发布/开发 模式,并允许在本地运行原生测试。只要你不使用反射或JNI,根据GraalVM的配置就是可行的。否则,你将不得不自己配置graal编译器,然而现在也有解决方案。

延迟和吞吐量

Golang 和原生 Java 的测试结果比较接近,虽然平均来说 Golang 版本的测试结果略好一些。不过,Java Native版本的测试结果更稳定。Golang服务有时在1.25μs内完成响应,也有一部分需要7s才能完成。

"预热 "后的JVM版本结果也不差,但比Native或Go版本稍逊一筹。

CPU利用率

使用0.5核的时候,Go和native-java在负载下似乎都表现不佳,而用2核启动时,也没有明显改善。这可能是因为工作负载的瓶颈是IO。或者是因为gin/Netty的默认配置没有考虑到多核的问题。

而JVM版本则利用了所有给定的核心,并在各个维度上提升了性能。

内存使用率

在压力下,Java native 使用40MB,Golang 使用24MB。两种情况下都还不错,虽然Golang版本使用的内存几乎少了一倍。

JVM使用了140MB。和Quarkus官方的统计完全一样。对于JVM来说还不错,但比Golang版本多了近6倍。

启动时间

Golang和cloud-native java都能立即启动,然而JVM版本需要几秒钟(取决于分配的CPU),并且在启动时产生CPU峰值。如果配置不当,会导致k8s HPA发飙,并增加pods。

开发体验

这与其说是一个实际问题,不如说是一个宗教问题。Quarkus 使用了在 Java 世界中很常见的抽象(比如基于注解的DI)。它为你启动服务并创建连接池。它可以使用丰富的集合标准库和generics。然而,这可能感觉有点像黑魔法,一旦有些组件不工作,你会感觉很无助。此外,将 Java 代码编译成原生二进制并不是那么简单,有一些限制和注意事项是你必须知道的,并非每个Java库都能兼容原生编译。一旦使用一个不兼容的库(比如Guice),你就需要自己配置Graal VM。

Quarkus 和 Graal VM "相对 "较新。所以可能会有一些问题。但由于双模式(JVM或原生)。在原生版本的某些组件停止工作的情况下,总是有一个后备方案,这对任何新问题来说都是很好的变通方法。

另一方面,Golang 在成立10年后才承认它需要generics。而且它肯定不喜欢框架使用很多魔法操作。这在很多方面既是好事也是坏事。此外,尽管 Go 社区做的非常好,然而可用的工具和库还是相对较少。然而它的编译和构建过程更快/更简单。而且兼容每个Golang的包,没有java-native平台带来的限制。

结论

Java已经为云原生做好了准备,Golang并没有大幅度领先。相信未来Cloud Native Java会被大规模使用。

原文地址:https://medium.com/swlh/cloud-native-java-vs-golang-2a72c0531b05

译者注:翻译过程去掉了中间关于测试过程记录,因为测试结果在表格中已经记录了,测试的细节过于冗长。

活动预告

本文由高可用架构翻译,技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。

高可用架构

改变互联网的构建方式

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码