Java、Go和Rust間的比較

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!


本文對Java、Go和Rust之間的對比並非完全是基準測試,更多的是比較輸出的可執行文件大小、內存使用情況、CPU使用率、運行時要求,當然會有一個小基準測試用於獲取RPS數據,使得更容易理解這些數值。

爲了嘗試更合理比較這三者,我在這次比較中分別用每種語言寫了個Web服務。該Web服務非常簡單,提供了3個REST端點。

1

三個Web服務的存儲庫託管在GitHub上。

製品大小

介紹下我是如何構建二進制文件的。在Java示例中,我使用maven-shade-plugin插件並使用mvn package命令,Go則使用go build命令,最後是Rust則使用cargo build --release。

2

製品編譯的大小也取決於所選的庫/依賴項,因此,如果它們膨脹了,那麼編譯的程序也會是同樣的結果。在此處特定情況下,對於我所選擇的庫,上圖顯示是程序編譯的大小。

在下面單獨的部分中,我將構建所有三個程序並打包成Docker鏡像,並列出它們的大小,以及顯示每種語言所需的運行時開銷。更多細節如下。

內存使用情況

空閒狀態

3

什麼?在空閒運行時顯示內存佔用的Go和Rust版本的條形圖在哪?好吧,它們是有的,只是Java在JVM啓動程序,處於空閒時,什麼都不做的情況下,就消耗了高達160MB的內存。在Go的情況下,程序使用了0.86 MB,在Rust的情況下使用0.36 MB。這是一個非常大的區別!在這裏,Java比Go和Rust對應的程序多用了兩個數量級的內存,只是空跑內存什麼也不做。這是對資源的巨大浪費。

提供REST請求

我們使用wrk來請求API,並觀察內存和CPU使用情況,以及三個版本的程序的每個端點在我的機器上的每秒請求數。

wrk -t2 -c400 -d30s http://127.0.0.1:8080/hello 
wrk -t2 -c400 -d30s http://127.0.0.1:8080/greeting/Jane
wrk -t2 -c400 -d30s http://127.0.0.1:8080/fibonacci/35

以上wrk命令表示,使用兩個線程(用於wrk),並在池中保持400個開啓的連接,並反覆調用GET端點,持續30秒。此處我只使用兩個線程,是因爲wrk跟被測試的程序都運行在同一臺機器上,因此我不想它們在可用資源,尤其是CPU上相互競爭。

每個Web服務都單獨測試,且每次運行測試都會重啓Web服務。

以下是每個版本的程序三次運行中的最佳結果。

/hello

該端點返回一個“Hello, World!”的消息。它分配字符串 "Hello, World!",並將其序列化,以JSON格式返回。

4

5

6

/greeting/{name} 

該端點接受段路徑參數{name},然後將字符串"Hello,{name}"格式化,序列化並返回以JSON格式的問候信息。

7

8

9

/fibonacci/{number} 

該端點接受段路徑參數{number}並以JSON格式序列化返回輸入的數字和斐波那契數。

對於這個特定的端點,我選擇用遞歸的形式來實現它。我知道,毫無疑問,迭代實現可以獲得更好的性能結果,而且出於生產目的,應該選擇迭代形式,但是在生產代碼中,有些情況下必須使用遞歸(非特指專用於計算斐波那契數)。因此我想讓這個實現與CPU堆棧分配密切相關。

1

2

3

在/fibonacci端點測試中,Java實現是唯一一個出現150次請求超時的,wrk輸出如下所示:

4

5

運行時大小

爲了模仿真實世界的雲原生應用,並消除"它在我的機器上正常!"這種情況,我爲這三個應用分別創建了一個Docker鏡像。

Docker源文件包含在存儲庫中相應程序的文件夾下。

我使用openjdk:8-jre-alpine作爲Java應用的基礎運行時鏡像,它是已知的最小的鏡像之一。然而這帶來了一些需要注意的事項,可能適用,也可能不適用於你的應用。主要是alpine鏡像在處理環境變量名方面不符合posix標準,所以你不能在Docker文件中使用帶.(點)的ENV(也不是什麼大事),另一個是alpine Linux鏡像是用musl libc而不是glibc編譯的,這意味着如果你的應用程序依賴於需要glibc存在的東西,它就無法工作。就我而言,alpine很好用。

至於Go和Rust版本的應用,我使用了靜態編譯,這意味着它們在運行時鏡像中不需要任意libc(glibc、musl等等),也意味着它們不需要一個帶OS的基礎鏡像來運行。所以我使用了scratch鏡像,這是一個no-op(無操作?)鏡像,它託管編譯後的可執行文件,零開銷。

我使用的Docker鏡像命名約定是{lang}/webservice。Java、Go和Rust版本的應用程序的鏡像大小分別是113MB、8.68MB和4.24 MB。

6

結論

7

在得出任何結論之前,我想指出這三種語言之間的關係(或者說缺乏關係)。Java和Go都是垃圾收集型語言,然而,Java是提前編譯(AOT)爲在JVM上運行的字節碼。當Java應用程序啓動時,會調用Just-In-Time(JIT)編譯器來優化字節碼,隨時隨地將其編譯成本地代碼,以提高應用程序的性能。

Go和Rust都是提前編譯成原生代碼,在運行時不會發生進一步的優化。

Java和Go都是垃圾收集類型語言,存在STW的副作用。意味着每當垃圾回收器運行的時候,它就會停止應用程序,進行垃圾回收,當垃圾回收結束後再從之前的狀態中恢復。大部分垃圾回收器需要停止程序,但是也有一些實現不需要這樣子。

當Java在90年代誕生時,它最大的賣點之一就是“一次編寫,隨處運行”。在當時這是非常棒的,因爲當時市場上還沒有很多虛擬化解決方案。如今,大多數CPU都支持虛擬化,在代碼可以在任何地方(無論在任何受支持的平臺上)運行的前提下,使用一種語言進行開發的誘惑就消失了。Docker和其他解決方案提供了廉價的虛擬化。

在整個測試過程中,Java版本的應用比Go或Rust對應的應用消耗了更多的內存,在數量級上,前兩次測試中,Java使用的內存大約多出8000%。這意味着對於現實世界的應用來說,Java應用的運營成本更高。

在前兩項測試中,Go應用程序的CPU使用量比Java少了20%左右,而服務的請求卻多了38%。另一方面,Rust版本的CPU使用量比Go少57%,而服務的請求量卻多13%。

第三個測試在設計上就是CPU密集型的,我希望儘可能地利用CPU。Go和Rust都比Java多利用了1%的CPU。而且我想如果wrk不是在同一臺機器上運行的話,這三個版本的CPU都會達到100%的上限。在內存方面,Java比Go和Rust多利用了2000%以上的內存。Java比Go多服務20%左右的請求,而Rust比Java多服務15%左右的請求。

在寫這篇文章的時候,Java編程語言已經存在了近三十年,這使得在市場上找到Java開發者相對容易一些。另一方面,Go和Rust都是相對較新的語言,所以相對於Java來說,自然而然的數量或開發人員就少了。儘管如此,Go和Rust都得到了很多關注,許多開發人員在新項目中採用了它們,並且有許多在生產環境中運行的項目使用Go和Rust,因爲簡單地說,它們在資源需求方面比Java更高效。(也可能是因爲它們是比較新的酷炫語言)

我在寫這篇文章的程序時,我學會了Go和Rust。就我而言,Go的學習曲線很短,因爲它是一門比較容易上手的語言,而且語法相對於其他語言來說也很小。我只花了幾天時間就用Go寫好了程序。關於Go,有一點需要注意的是編譯速度,我不得不承認,與Java/C/C++/Rust等其他語言相比,Go的編譯速度極快。Rust版本的程序我花了一週左右的時間才完成,我不得不說,大部分時間都花在了借用檢查器(borrow checker)上。Rust有嚴格的所有權規則,但一旦掌握了Rust中所有權和借用的概念,編譯器的錯誤信息就會突然變得更有意義。Rust編譯器之所以在違反借用檢查規則時對你“諄諄教誨”(無情報錯),是因爲編譯器希望在編譯時證明分配的內存的生存期和所有權。通過這樣做,它保證了程序的安全性(例如:沒有懸空指針,除非使用了不安全的代碼逃逸), 並且在編譯時確定了釋放位置,從而消除了對垃圾收集器的需求和運行時成本。當然,這是以學習Rust的所有權系統爲代價的。

就競爭而言,在我看來,Go是Java(通常是JVM語言)的直接競爭對手,但不是Rust的競爭對手。另一方面,Rust是Java、Go、C和C++的有力競爭者。

因爲它們的效率,我認爲我自己將會用Go和Rust寫更多的程序,但很可能用Rust寫得更多。它們都很適合於Web服務、CLI、系統程序等等的開發。然而,Rust比Go有一個根本的優勢。它不是一種垃圾收集的語言,而且與C和C++相比,它的設計是爲了安全地編寫代碼。例如,Go並不特別適合用來寫操作系統內核,這也是Rust的優勢所在,它與C/C++競爭,因爲它們是長期存在的、事實上的寫操作系統的語言。Rust與C/C++競爭的另一個層面是在嵌入式世界,我們將在以後再討論這個。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-07-21
本文作者:馮旭松
本文來自:“dockone”,瞭解相關信息可以關注“dockone”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章