雲原生時代高效能Java框架—Quarkus(一)

東溪陳姓少年發表於2020-07-17

——— Quarkus&GraalVM介紹、建立並啟動第一個專案


Quarkus系列博文


Quarkus介紹

Quarkus 是一個為 Java 虛擬機器(JVM)原生編譯(native compilation)而設計的全棧Kubernetes 原生 Java 框架,用於優化Java特別是Java專案的容器化,並使其成為serverlessKubernetes 環境的高效平臺。

Quarkus 可與常用 Java 標準、框架和庫協同工作,例如 Eclipse MicroProfile、Apache Kafka、RESTEasy(JAX-RS)、Hibernate ORM(JPA)、Spring、Infinispan、Camel 等。

Quarkus 的依賴注入解決方案基於 CDI(上下文和依賴注入),且包含一個擴充套件框架來擴充套件功能並將其配置、引導並整合到您的應用中。新增擴充套件就像新增依賴項一樣容易;或者,您可以使用 Quarkus 工具。

此外也是引人注目的一個特點,它還向 GraalVM(一種通用虛擬機器,用於執行以多種語言(包括 Java 和 JavaScript)編寫的應用)提供正確資訊,以便對應用進行原生編譯。

Rad Hat列出了一下清單來表明使用Quarkus的好處:檢查清單

Quarkus與傳統Java框架對比

imgQuarkus與傳統技術棧對比

來自官方的一張圖,展示了使用Quarkus框架開發專案和使用傳統框架開發的一些執行時資料明細對比,可以看到Quarkus專案在JVM中執行時所消耗的記憶體和介面響應能力要明顯好於傳統的Java技術棧。而將Quarkus編譯成本地可執行檔案(本地映象)之後,其優勢可以說非常明顯了。

GraalVM簡介

GraalVM是一種高效能的虛擬機器,它可以顯著的提高程式的效能和執行效率,非常適合微服務。其設計初衷是實現可以執行不同語言(Java、JavaScript、基於LLVM的語言(例如C和C ++)以及其他動態語言)編寫的應用程式。它消除了不同程式語言之間的隔閡,並實現了多語言共享執行時的互操作性。它可以獨立執行,也可以在OpenJDK,Node.js或Oracle資料庫的上下文中執行。

GraalVM system diagram

對於Java應用程式,GraalVM可以帶來很多有價值的好處:更快地執行它們,通過指令碼語言(JavaScript, R, Python...)提供可擴充套件性或建立提前編譯的本機映像(native-image)。

更多關於GraalVM的資訊可參考:此篇文章

GraalVM安裝

本文我們使用SDKMAN來安裝GraalVM。SDKMAN是一款用於在大多數基於Unix的系統上管理多個軟體開發套件的並行版本的工具。它提供了一個方便的命令列介面(CLI)和API,用於安裝,切換,刪除和列出候選人。它以前被稱為Groovy enVironment Manager (GVM),受到了非常有用的RVM和rbenv工具的啟發,該工具在Ruby社群中廣泛使用。

安裝SDKMAN

執行如下命令進行安裝:

$ curl -s "https://get.sdkman.io" | bash
$ source "$HOME/.sdkman/bin/sdkman-init.sh"	

執行如下命令,驗證是否已安裝ADKMAN:

$ sdk version

安裝GraalVM

執行如下命令:

$ sdk list java

可以看到SDKMAN列出了所支援的所有Java發行版

image-20200717142755813

我們找到GraalVM的發行版

image-20200717142840033

截至編寫本文時,GraalVM的最新版本為20.1.0.r11-grl,所以我們會安裝此版本。執行如下命令安裝GraalVM:

$ sdk install java 20.1.0.r11-grl

至此,GraalVM安裝完畢!我們可以執行如下命令來判斷GraalVM是否已安裝:

$ java -version

image-20200717143216643

建立專案

我們有多種方式建立Quarkus專案

使用Intellij IDEA建立Quarkus專案

點選選單欄File>New>Project... 建立新專案

image-20200717150609041

點選Next,並填寫適當的資訊,Next>Next...,建立完畢。

使用Maven命令列建立Quarkus專案

執行如下命令,建立Quarkus專案:

mvn io.quarkus:quarkus-maven-plugin:1.6.0.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=getting-started \
    -DclassName="org.acme.getting.started.GreetingResource" \
    -Dpath="/hello"
cd getting-started

至此,建立專案完畢!

啟動專案

我們使用IDEA開啟專案

image-20200717152929281

Quarkus並沒有類似Spring Boot、Helidon之類框架一樣的啟動類,我們需要通過執行Maven命令來啟動專案。

在IDEA控制檯執行如下命令來啟動專案:

./mvnw compile quarkus:dev

啟動成功!

image-20200717153314096

當然每次執行命令列會顯得不便,我們可以通過如下配置來配置專案快捷啟動:

image-20200717153444892

點選左上角"+"圖示新增一個Maven配置如左邊欄,在右邊欄中的Command line中填入"compile quarkus:dev",點選OK。

image-20200717153542033

此時可以點下下圖所示圖示來便捷啟動專案

image-20200717153914940

執行測試

開啟專案中的測試類,看到如下程式碼:

@QuarkusTest  //1
public class ExampleResourceTest {
    @Test
    public void testHelloEndpoint() {
        given()
            .when().get("/hello")
            .then()
            .statusCode(200) //2
            .body(is("hello"));
    }
}
  1. 通過使用@QuarkusTest註解執行程式,可以指示JUnit在測試之前啟動應用程式。
  2. 檢查HTTP響應狀態程式碼和內容。

預設情況下,測試將在埠8081上執行,以免與正在執行的應用程式衝突。Quarkus自動將RestAssured配置為使用此埠。如果要測試其他路徑,則可以使用@TestHTTPResource註解將被測試的URL直接注入到測試類的欄位中。該欄位的型別可以是字串,URL或URI。我們需要為該註解指定測試路徑的值。例如,如果我要測試對映到/myservlet的Servlet,只需在測試中新增以下內容:

@QuarkusTest  
public class ExampleResourceTest {
    @TestHTTPResource("/myservlet")
    URL testUrl;

    @Test
    public void testHelloEndpoint() {
        given()
            .when().get(testUrl)
            .then()
            .statusCode(200) 
            .body(is("hello"));
    }
}

可以通過在專案配置檔案中配置quarkus.http.test-port屬性控制測試埠。 Quarkus還建立了一個名為test.url的系統屬性,該屬性值將被設定成基礎測試URL(BasePath)。

總結

我們進入了雲原生、微服務的時代,我們告別了大型單體應用的龐大和複雜,並且收穫了微服務帶來的極大的好處 。但是一些問題也開始接踵而至。隨著微小服務的增多,曾經在單個應用上發生的多餘無用依賴、Java專案與生俱來的啟動過程緩慢、JIT優化問題擴散到了每個微服務上面。而且傳統的Java EE規範並沒有微服務的模式解決方案,問題很迫切需要解決。幸運的事,隨著Quarkus、Helidon等等一些新型Java開發框架的出現緩解了這個局面(以及目前Spring生態也開始了對GraalVM的大力支援),他們使Java變得更加本地化,不管是專案的體量方面還是資源消耗和執行效率方面都有顯著提升。

相關文章