這篇文章主要講解了“云原生時(shí)代是Java還是Go”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“云原生時(shí)代是Java還是Go”吧!
恒山網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),恒山網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為恒山成百上千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站制作要多少錢,請找那個(gè)售后服務(wù)好的恒山做網(wǎng)站的公司定做!
Java曾經(jīng)著名的座右銘:"一次編寫,到處運(yùn)行",已經(jīng)很過時(shí)了,因?yàn)楝F(xiàn)在我們只想在容器里運(yùn)行代碼。在容器里,一個(gè) "Just in time "的編譯器意義不大。
出于這個(gè)原因,可能為了更好地適應(yīng)云計(jì)算,Java生態(tài)系統(tǒng)正處于轉(zhuǎn)型之中。Oracle 的GraalVm允許將字節(jié)碼編譯成Linux可執(zhí)行文件(ELF),而Rad Heat的Quarkus以及其他框架,則立志讓響應(yīng)式服務(wù)這件事變得更簡單。Quarkus以Netty和Vertx.x為核心,可以用來構(gòu)建非常高效的響應(yīng)式Web服務(wù)。
Java編譯成可執(zhí)行二進(jìn)制文件,以毫秒級(jí)的速度啟動(dòng),內(nèi)存占用很小。這樣就可以利用Java生態(tài)系統(tǒng),甚至可以用其他JVM語言(如Scala和Kotlin)編寫。你可以用online項(xiàng)目生成器玩玩Quarkus,或者用maven插件在本地生成一個(gè)項(xiàng)目。
而Golang則是為云而生的,在容器中運(yùn)行時(shí),沒有遺留負(fù)擔(dān)。它被認(rèn)為是云端的編程語言。生成的二進(jìn)制可執(zhí)行文件很小,快速啟動(dòng),內(nèi)存占用也很小,而且這是從Go誕生之初就具備的特性。Golang的流行對(duì) Java 世界形成了嚴(yán)峻的挑戰(zhàn)。
Java有機(jī)會(huì)嗎,也許只有時(shí)間才會(huì)告訴我們最終答案。然而,出于好奇,我想從性能和開發(fā)體驗(yàn)方面比較一下 Java 和 Golang 的云原生服務(wù)。
在這篇文章中,我將使用兩種語言來寫同樣的服務(wù)。比較它們的CPU使用率、RAM、延遲和運(yùn)行速度。這些服務(wù)將在容器中啟動(dòng),資源分配相同,使用ab來測試。
對(duì)于我的案例來說,這是一個(gè) "足夠好 "的基準(zhǔn),因?yàn)槲也患僭O(shè)找到最好/最差的基準(zhǔn)結(jié)果,而是在同一環(huán)境下執(zhí)行運(yùn)行兩個(gè)基準(zhǔn)測試進(jìn)行比較。
場景
這兩個(gè)服務(wù)將連接到在另一個(gè)容器中運(yùn)行的MySQL數(shù)據(jù)庫,有一個(gè)表和三行數(shù)據(jù)。
每一個(gè)服務(wù)都會(huì)獲取所有記錄,將它們轉(zhuǎn)化為對(duì)象,然后輸出JSON數(shù)組。
ab將發(fā)出10K請求,并發(fā)級(jí)別為100,quarkus JVM版本運(yùn)行兩次(用于測試 "冷"/"暖 "JVM)。
Go語言版本
Go語言版本使用gin框架。
# the service package 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 HANDLER func 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驅(qū)動(dòng)的使用go-sql-driver。golang的代碼風(fēng)格是非常明確的。一種一切都在眼前態(tài)度。主函數(shù)啟動(dòng)服務(wù)器,配置請求處理程序,打開DB連接。
編譯本地可執(zhí)行文件
Kotlin版本
package org.acme import io.vertx.core.json.JsonArray import io.vertx.core.json.JsonObject import io.vertx.mutiny.mysqlclient.MySQLPool import io.vertx.mutiny.sqlclient.Row import io.vertx.mutiny.sqlclient.RowSet import java.util.concurrent.CompletionStage import javax.inject.Inject import javax.ws.rs.GET import javax.ws.rs.Path import javax.ws.rs.Produces import javax.ws.rs.core.MediaType @Path("/fruits") class FruitResource { @field:Inject lateinit var client: MySQLPool @GET @Produces(MediaType.APPLICATION_JSON) fun listFruits(): CompletionStage{ return client.query("SELECT * FROM fruits").execute() .map { rows: RowSet -> rows.fold(JsonArray()) { array, row -> array.add(JsonObject() .put("id", row.getLong("id")) .put("name", row.getString("name"))) } }.subscribeAsCompletionStage() } }
數(shù)據(jù)庫連接使用Quarkus React Mysql 擴(kuò)展。
與Go版本相比,代碼有很大不同,比如CDI依賴注入,使用javax注釋的聲明式路由,自動(dòng)配置解析,以及數(shù)據(jù)源/連接創(chuàng)建/服務(wù)器引導(dǎo)。這是使用框架的代價(jià),它為你完成了繁重的工作,并決定了做事方式。不過,它比go版本代碼要簡短很多。
這里使用Netty響應(yīng)式web服務(wù)器,由Vert.x多事件循環(huán)包裝,還有一個(gè)Vert.x響應(yīng)式MySQL驅(qū)動(dòng),這樣可以用一個(gè)線程處理多個(gè)DB連接。
另外,我可以使用Kotlin的集合庫的fold函數(shù),這種函數(shù)還沒有通用的Go版本。
編譯Java版本的可執(zhí)行文件
我已經(jīng)弄清楚構(gòu)建過程中發(fā)生了什么,其核心是SubstrateVM。它被設(shè)計(jì)在AOT過程中的可嵌入虛擬機(jī),它會(huì)鏈接到我們的代碼,并作為一個(gè)單元進(jìn)行編譯。然而根據(jù)Oracle的說法,SubstrateVM的優(yōu)化比HotSpot Vm少,垃圾收集器也比較簡單。
該AOT編譯器被稱為 "Graal",它是語言不相關(guān)的。java字節(jié)碼需要被翻譯成一種中間表示法(Truffle語言)。這在這篇文章【1】中可以找到關(guān)于Graal和Truffle的相關(guān)論述。
構(gòu)建一個(gè) Java 本地可執(zhí)行文件看起來更復(fù)雜,編譯得更慢,它產(chǎn)生的二進(jìn)制文件幾乎是Go版本兩倍大小。然而一個(gè)35M的可執(zhí)行二進(jìn)制文件和Java FatJar相比,還是小D多了。35MB甚至可以讓你使用aws lambda運(yùn)行。
壓力測試
我在本機(jī)運(yùn)行所有測試,設(shè)置如下。
MacBook Pro(15英寸,2017年
2.9 GHz英特爾酷睿i7(8個(gè)核心)。
16 GB 2133 MHz LPDDR3
使用cAdvisor的工具來監(jiān)控容器的統(tǒng)計(jì)數(shù)據(jù)。
場景
Quarkus JVM hotspot
Quarkus Java native
Golang
上述的每種情況都在以下三種配置上測試
100MB / 0.5 CPU | 200MB / 1 CPU | 300MB / 2 CPU
我主要關(guān)注:
cpu/ram利用率(多核的利用率)
cpu/ram峰值
cpu/ram空余
啟動(dòng)時(shí)間
響應(yīng)延遲avg/max
吞吐量(每秒請求數(shù))
測試結(jié)果
看起來Quarkus已經(jīng)為生產(chǎn)環(huán)境做好準(zhǔn)備了,它允許簡單的JVM/原生發(fā)布/開發(fā) 模式,并允許在本地運(yùn)行原生測試。只要你不使用反射或JNI,根據(jù)GraalVM的配置就是可行的。否則,你將不得不自己配置graal編譯器,然而現(xiàn)在也有解決方案。
延遲和吞吐量
Golang 和原生 Java 的測試結(jié)果比較接近,雖然平均來說 Golang 版本的測試結(jié)果略好一些。不過,Java Native版本的測試結(jié)果更穩(wěn)定。Golang服務(wù)有時(shí)在1.25μs內(nèi)完成響應(yīng),也有一部分需要7s才能完成。
"預(yù)熱 "后的JVM版本結(jié)果也不差,但比Native或Go版本稍遜一籌。
CPU利用率
使用0.5核的時(shí)候,Go和native-java在負(fù)載下似乎都表現(xiàn)不佳,而用2核啟動(dòng)時(shí),也沒有明顯改善。這可能是因?yàn)楣ぷ髫?fù)載的瓶頸是IO?;蛘呤且?yàn)間in/Netty的默認(rèn)配置沒有考慮到多核的問題。
而JVM版本則利用了所有給定的核心,并在各個(gè)維度上提升了性能。
內(nèi)存使用率
在壓力下,Java native 使用40MB,Golang 使用24MB。兩種情況下都還不錯(cuò),雖然Golang版本使用的內(nèi)存幾乎少了一倍。
JVM使用了140MB。和Quarkus官方的統(tǒng)計(jì)完全一樣。對(duì)于JVM來說還不錯(cuò),但比Golang版本多了近6倍。
啟動(dòng)時(shí)間
Golang和cloud-native java都能立即啟動(dòng),然而JVM版本需要幾秒鐘(取決于分配的CPU),并且在啟動(dòng)時(shí)產(chǎn)生CPU峰值。如果配置不當(dāng),會(huì)導(dǎo)致k8s HPA發(fā)飆,并增加pods。
開發(fā)體驗(yàn)
這與其說是一個(gè)實(shí)際問題,不如說是一個(gè)宗教問題。Quarkus 使用了在 Java 世界中很常見的抽象(比如基于注解的DI)。它為你啟動(dòng)服務(wù)并創(chuàng)建連接池。它可以使用豐富的集合標(biāo)準(zhǔn)庫和generics。然而,這可能感覺有點(diǎn)像黑魔法,一旦有些組件不工作,你會(huì)感覺很無助。此外,將 Java 代碼編譯成原生二進(jìn)制并不是那么簡單,有一些限制和注意事項(xiàng)是你必須知道的,并非每個(gè)Java庫都能兼容原生編譯。一旦使用一個(gè)不兼容的庫(比如Guice),你就需要自己配置Graal VM。
Quarkus 和 Graal VM "相對(duì) "較新。所以可能會(huì)有一些問題。但由于雙模式(JVM或原生)。在原生版本的某些組件停止工作的情況下,總是有一個(gè)后備方案,這對(duì)任何新問題來說都是很好的變通方法。
另一方面,Golang 在成立10年后才承認(rèn)它需要generics。而且它肯定不喜歡框架使用很多魔法操作。這在很多方面既是好事也是壞事。此外,盡管 Go 社區(qū)做的非常好,然而可用的工具和庫還是相對(duì)較少。然而它的編譯和構(gòu)建過程更快/更簡單。而且兼容每個(gè)Golang的包,沒有java-native平臺(tái)帶來的限制。
感謝各位的閱讀,以上就是“云原生時(shí)代是Java還是Go”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)云原生時(shí)代是Java還是Go這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!