來源:juejin.cn/post/7023317351563001886 1、概述 SpringBoot框架不用多介紹,Java程式員想必都知道。相對來說熟悉Quarkus的人可能會少一些。Quarkus首頁放出的標語:超音速亞原子的Java(Supersonic Subatomic Java)。 ...
來源:juejin.cn/post/7023317351563001886
1、概述
SpringBoot框架不用多介紹,Java程式員想必都知道。相對來說熟悉Quarkus的人可能會少一些。Quarkus首頁放出的標語:超音速亞原子的Java(Supersonic Subatomic Java)。
它是為 OpenJDK HotSpot 和 GraalVM 量身定製的 Kubernetes Native Java 框架,基於同類最佳的 Java 庫和標準製作而成。Quarkus 的到來為開發 Linux 容器和 kubernetes 原生 Java 微服務帶來了一個創新平臺。
在本文中,我們將對這兩個 Java 框架 Spring Boot 和 Quarkus 進行簡單的比較。我們可以更好地瞭解它們之間的異同,以及一些特殊性。我們還會執行一些測試來衡量它們的性能。最後,我們會介紹一個開發人員如何從Spring轉換到Quarkus。
2、SpringBoot
Spring Boot 是一個基於 Java 的框架,專註於企業應用。它可以簡單使用所有 Spring 項目,並集成了許多開箱即用的功能,來幫助開發人員提高生產力。
Spring Boot減少了配置和樣板代碼的數量。此外,由於其約定優於配置方法,它根據依賴項自動註冊預設配置,大大縮短了 Java 應用程式的開發周期。
Spring Boot 基礎就不介紹了,推薦看這個實戰項目:
3、Quarkus
Quarkus 是另一個採用與上述 Spring Boot 類似方法的框架,但還有一個額外的優點,即以更快的啟動時間、更好的資源利用率和效率交付更小的工件(Supersonic、Subatomic)。
它針對雲、無伺服器和容器化環境進行了優化。儘管側重點略有不同, Quarkus 也能與最流行的 Java 框架很好地集成。
4、比較
如上所述,這兩個框架都與其他項目和框架有很好的集成。但是,它們的內部實現和架構是不同的。例如,Spring Boot 提供兩種類型的 Web 功能:阻塞(Servlets)和非阻塞(WebFlux)。
另一方面,Quarkus 也提供這兩種方法,但與 Spring Boot 不同的是,它允許我們同時使用阻塞和非阻塞方法。此外,Quarkus 在其架構中嵌入了反應式編程方法。
為了在我們的比較中獲得更準確的數據,我們將使用兩個完全響應式的應用程式,這些應用程式使用 Spring WebFlux 和 Quarkus 響應式功能實現。
此外,Quarkus 項目中最重要的功能之一是能夠創建原生鏡像(Native Images,基於特定平臺的可執行二進位文件)。因此,我們還將在比較中包含兩個原生映像,但 Spring 的原生鏡像支持仍處於試驗階段。另外我們需要用到 GraalVM。
測試應用
我們的應用程式將實現三個 API:一個允許用戶創建郵政編碼,另一個用於查找特定郵政編碼的信息,最後按城市查詢郵政編碼。這些 API 是使用了前面提到的 Spring Boot 和 Quarkus 的反應式方法實現的,資料庫使用的是PostgreSQL。
我們的目標是創建一個比 HelloWorld 程式稍微複雜一些的樣常式序。當然,資料庫驅動和序列化框架等內容的實現會影響我們的比較結果。但是,大多數應用程式可能都會需要處理這些事情。
因此,比較的目的並不是為了證明哪個框架更好或更高效,而是分析研究這些特定實現的一個案例。
測試計劃
為了測試這兩種實現,我們將使用 JMeter 執行測試,並分析其測試報告。此外,我們將使用 VisualVM 在執行測試期間監控應用程式的資源利用率。
測試將運行 5 分鐘,會調用所有 API,從預熱期開始,然後增加併發用戶數,直到達到 1,500。我們將在前幾秒鐘開始填充資料庫,然後開始查詢,如下所示:
所有測試均在以下規格的機器上進行:
由於缺乏與其他後臺進程的隔離,最終結果可能不太理想,但正如前面提到的,我們無意對這兩個框架的性能進行廣泛而詳細的分析。
5、調查結果
對開發人員來說,這兩個項目的體驗都很棒,但值得一提的是 Spring Boot 有更好的文檔,在網上也可以找到更多資料。Quarkus 在這方面正在改進,但仍然有點落後。
在指標方面,我們有如下結果:
通過這個實驗,我們可以觀察到 Quarkus 在 JVM 和原生版本的啟動時間方面幾乎比 Spring Boot 快一倍。構建時間也快得多。在原生鏡像的情況下,構建耗時:9 分鐘(Quarkus)對 13 分鐘(Spring Boot),JVM 構建耗時:20 秒(Quarkus)對 39 秒(Spring Boot)。
Artifact(工件)的大小出現了同樣的情況,Quarkus 生成了更小的工件而再次領先。原生映像:75MB (Quarkus) 對 109MB (Spring Boot),以及JVM 版本:4KB (Quarkus) 對 26MB (Spring Boot)。
關於其他指標,結論並不是那麼顯而易見。因此,我們需要更深入地瞭解一下。
CPU
我們看到 JVM 版本在預熱階段開始時消耗更多的 CPU。之後CPU使用率趨於穩定,所有版本的消耗相對均等。
以下是 JVM 和 Native 版本中 Quarkus 的 CPU 消耗:
JVM 版的 Quarkus ↑↑↑
Native 版的 Quarkus ↑↑↑
記憶體
記憶體就更複雜了。首先,很明顯,兩個框架的 JVM 版本都為Heap(堆)預留了更多記憶體。儘管如此,Quarkus 從一開始就預留了較少的記憶體,啟動期間的記憶體利用率也是如此。
然後,查看測試期間的利用率,我們可以觀察到Native版本似乎不像 JVM 版本那樣有效或頻繁地回收記憶體。可以通過調整一些參數來改善這一點,在這個比較中,我們使用了預設參數,並沒有對 GC、JVM 選項或任何其他參數進行更改。
讓我們看一下記憶體使用圖:
Spring Boot JVM ↑↑↑
Quarkus JVM ↑↑↑
Spring Boot 原生 ↑↑↑
Quarkus 原生 ↑↑↑
在測試期間儘管Quarkus出現了更高的峰值,但確實消耗的記憶體資源更少。
響應時間
最後,關於響應時間和峰值使用的線程數,Spring Boot 似乎略微具有優勢。它能夠使用更少的線程處理相同的負載,同時還具有更好的響應時間。
Spring Boot Native 版本在這種情況下表現出更好的性能。但是讓我們看看每個版本的響應時間分佈:
Spring Boot JVM ↑↑↑
儘管有更多異常值,但 Spring Boot JVM 版本隨著時間的推移取得了最好的進展,這很可能是由於 JIT 編譯器優化[1]。
Quarkus JVM ↑↑↑
Spring Boot 原生 ↑↑↑
Quarkus 原生 ↑↑↑
Quarkus 在低資源利用率方面表現出強大的實力。然而,至少在這個實驗中,Spring Boot 在吞吐量和響應能力方面與Quarkus旗鼓相當。
這兩個框架都能夠處理所有請求而沒有任何錯誤。不僅如此,他們的表現也十分相似,並沒有太大的差距。
總而言之
考慮到所有因素,在實現 Java 應用程式時,這兩個框架都是很好的選擇。
Native程式速度快且資源消耗低,是無伺服器、短期(short-living)應用和資源消耗敏感環境的絕佳選擇。
另一方面,JVM 應用程式似乎有更多的開銷,但隨著時間的推移具有出色的穩定性和高吞吐量,非常適合健壯、長壽命的應用程式。
測試程式的代碼和用於測試它們的腳本可以在 GitHub 上找到[2]。
6、從 Spring 轉換到 Quarkus
隨著K8s的興起,對原生應用支持良好的Quarkus框架也越來越受到關註很多開發人員在考慮從 Spring 轉換到 Quarkus。然而,開發人員在開始評估新的框架時通常必須擱置他們現有的知識。
幸運的是, Quarkus 不一樣,因為它是由一群在 Java 技術方面具有深厚專業知識的工程師創建的。這包括 Spring API 相容性,創建Quarkus的工程師同時也是在 Red Hat Runtime 上為 Spring Boot 提供支持的工程師。
推薦一個開源免費的 Spring Boot 實戰項目:
7、我是 Spring 開發者,為什麼要選Quarkus?
越來越明顯的是,容器化,尤其是 Kubernetes,正在迫使人們重新評估 Java ,用於開發雲原生應用程式。Kubernetes 是一種高度動態的共用基礎設施。由於集群中托管的應用程式數量的增長以及對應用程式生命周期變化的響應能力的提高(例如重新部署和向上/向下擴展),基礎設施的投入變得更加划算。
傳統的 Java 雲原生運行時在現有的棧上增加了新的分層,而沒有真正重新考慮底層。這導致更大的記憶體消耗和更慢的啟動時間,以至於現在很多公司為了從 Kubernetes 集群的大量投資中獲得更多價值,願意放棄他們深厚的 Java 專業知識,為 Go 和 Node.js 重新培養人才和開發工具。
傳統雲原生 Java 棧 ↑↑↑
這正是 Quarkus 解決的問題。Quarkus 針對記憶體使用率和快速啟動時間進行了優化。與其他雲原生 Java 棧相比,在 JVM 上運行的 Quarkus 應用可以在相同數量的RAM中提供近兩倍的應用程式實例,並且當打包為原生二進位文件時,實例數量增加了 7 倍。
這不僅僅是使用 SubstrateVM[3](GraalVM 的一個特性)簡單地編譯為原生二進位文件。
Quarkus 專為 Kubernetes 的基礎設施優化了傳統的 “高度動態”框架,從而降低了記憶體利用率並加快了初始啟動速度,結果是運行時效率的顯著提高。這些經過優化且文檔齊全的框架稱為“擴展”,由同類最佳的標準 API 組成。
運行時效率 ↑↑↑
Quarkus 棧 ↑↑↑
我司為什麼要從 Spring Boot 遷移到 Quarkus?
以我們公司為例,我司的舊系統基於 Spring 和 Tomcat。當我們維護和部署時,這個傳統的框架給我們帶來了一些困擾,基於以下原因我們決定遷移到Quarkus:
- 記憶體和 CPU 消耗:對於正在執行的操作,Spring 和 Tomcat 框架在應用的主要目的之外使用了過多的資源。
- 預熱時間:Spring 應用程式可能需要 10-20 秒的時間才能啟動,之後應用程式才可以開始預熱。
- 無用的代碼:作為開發人員,我們都討厭樣板代碼(boilerplate code)。
- 測試:Quarkus 讓編寫單元測試和集成測試變得非常容易。只需在那裡打一個@QuarkusTest 註釋,它實際上會啟動整個應用程式以運行您的測試。
- 橫向擴展(Scale-out) vs. 縱向擴展(Scale-up):每個應用程式越小(資源方面),我們可以添加的越多。在這裡橫向可擴展性勝出。
- 學習曲線:Quarkus 的線上文檔非常簡單易懂。
8、Spring 開發者可以活用哪些現有知識?
Quarkus 的 Spring API 相容性包括 Spring DI、Spring Web 和 Spring Data JPA。同時也在計劃其他 Spring API,如 Spring Security 和 Spring Config。在 JVM 上運行時,Quarkus 應用程式幾乎可以利用任何 Java 庫。只要不使用 Java 反射,這些Java庫就可以編譯為原生。
例如,受 Spring 開發人員歡迎的 Lombok 庫就可以原生編譯。需要明確的是,Quarkus 中的 Spring API 相容性並非為了作為一個完整的 Spring 平臺來重新托管現有的 Spring 應用程式。目的是為了讓基於 Quarkus 開發新應用程式成為一種自然的入門體驗。結合預先優化的擴展,Quarkus 為微服務開發提供了大量的功能。很多開發人員已成功將 Spring 應用程式遷移到 Quarkus。
Spring 框架本質上是高度動態的。為瞭解決這個問題,Quarkus的Spring 相容性擴展將 Spring API 映射到現有擴展中的 API,這些擴展已經針對快速啟動、降低記憶體利用率和原生編譯進行了優化,例如 RestEasy 和 CDI。此外,Quarkus的Spring 相容性擴展不使用 Spring 應用程式上下文。由於這些原因,嘗試使用額外的 Spring 庫可能不會奏效。
推薦一個開源免費的 Spring Boot 實戰項目:
Quarkus Spring Web Example
import java.util.List;
import java.util.Optional;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/person")
public class PersonController {
@GetMapping(path = "/greet/{id}", produces = "text/plain")
public String greetPerson(@PathVariable(name = "id") long id) {
String name="";
// ...
return name;
}
@GetMapping(produces = "application/json")
public Iterable<Person> findAll() {
return personRepository.findAll();
}
Quarkus Spring Repository Example
package org.acme.springmp;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findByAge(int age);
}
Quarkus Spring Service + MicroProfile Fault Tolerance Example
import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Timeout;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service // Spring
public class PersonService {
@Autowired // Spring
@RestClient // MicroProfile
SalutationMicroProfileRestClient salutationRestClient;
@Value("${fallbackSalutation}") // Spring
String fallbackSalutation;
@CircuitBreaker(delay=5000, failureRatio=.5) // MicroProfile
@Fallback(fallbackMethod = "salutationFallback")// MicroProfile
public String getSalutation() {
return salutationRestClient.getSalutation();
}
9、對Spring開發者有額外的好處嗎?
除了提高記憶體利用率和啟動時間外,Quarkus 還為 Spring 開發人員提供了以下好處:
- 功能即服務 (FaaS) 。當編譯為原生二進位文件時,Quarkus 應用程式可以在 0.0015 秒內啟動,從而可以將現有的 Spring 和 Java API 知識與 FaaS 功能結合使用。(Azure、AWS Lambda)
- 實時編碼。從“Hello World”示例應用程式開始,然後將其轉換為複雜的微服務,而無需重新啟動應用程式。只需保存並重新載入瀏覽器即可查看沿途的變化。Quarkus 實時編碼“開箱即用”,與 IDE 無關。
- 支持反應式和命令式模型。 Quarkus 有一個反應式核心,支持傳統的命令式模型、反應式模型,或在同一應用程式中同時支持兩者。
- 早期檢測依賴註入錯誤。 Quarkus 在編譯期間而不是在運行時捕獲依賴項註入錯誤。
- 最佳框架和標準的結合。Quarkus 在同一應用程式中支持 Spring API 相容性、Eclipse Vert.x、MicroProfile(JAX-RS、CDI 等)、反應式流和消息傳遞等,可以在一個項目中同時使用 Spring 和 MicroProfile API。
10、Spring開發者如何開始學習Quarkus?
推薦的步驟包括:
- 參看入門指南[4]作為 Quarkus 的一般介紹。
- 參看 Spring DI[5]、Spring Web[6] 和 Spring Data JPA[7] 的指南。
- 使用 code.quarkus.io[8] 創建一個新應用。
參考資料:
- https://www.baeldung.com/spring-boot-vs-quarkus
- https://quarkus.io/blog/quarkus-for-spring-developers/
- https://www.logicmonitor.com/blog/quarkus-vs-spring
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!