10個Spring Boot效能最佳實踐

banq發表於2024-06-25

在本文中,我們將首先討論一般意義上的效能,然後討論 10 個 Spring Boot 效能最佳實踐,以使我們的 Spring Boot 快速且資源高效。

什麼是效能?
在現代軟體開發中,效能有不同的方面,這些方面在某種程度上與這兩者(執行時和資源效率)相關:

  • 可擴充套件性:在更高的工作負載、使用者數量或資料量下維持效能和功能的能力。
  • 可靠性:能夠保持一致並無中斷或錯誤地執行其預期功能。
  • 吞吐量:在特定時間內順利管理資料和任務的能力。

通常,軟體應用程式的效能就是確保其順利、快速、有效地執行。它還涉及高效管理資源和滿足使用者的期望。

1-儘可能使用最新版本的 Spring Boot
在 Spring Framework 和 Spring Boot 的每個版本中,除了引入新特性和功能外,還透過最佳化 Spring 核心容器和模組、修復錯誤等方式提高了效能。因此,強烈建議您儘可能多地使用最新版本的 Spring Boot。


2- JVM 版本和調優
與 Spring Boot 類似,每個Java LTS 版本都有很多效能改進。有時,為了利用 Spring Boot 最新版本中的效能改進,我們需要使用最新版本的 Java。

雖然最新版本的 JVM 會提高你的 Spring Boot 應用程式的效能,但 JVM 調優可以進一步提高我們的 Spring Boot 應用程式的效能。JVM 調優超出了本文的討論範圍,但我可以提到一些我們需要注意的領域:

  • 初始和最大堆大小使用-Xms和-Xmx
  • 其他 JVM 記憶體設定
  • 選擇合適的GC實現

最佳 JVM 和 GC 設定因應用程式和環境而異。測試各種配置和監控效能對於確定最佳設定至關重要。

3-在 JDK 21 上的 Web MVC 堆疊中使用虛擬執行緒
從 3.2 版開始,Spring Boot 開始以不同的方式支援虛擬執行緒(Project Loom)。

使用此配置,我們可以在 Spring Boot 中輕鬆啟用虛擬執行緒:

spring.threads.virtual.enabled=true

透過這種配置,Spring Boot Web MVC 將處理網路請求,如控制器中的方法,該請求將在虛擬執行緒上執行。

4- Spring AOT 和 Spring GraalVM 原生映象
GraalVM Native Images 提供了一種執行 Java 應用程式的新方法,與 JVM 相比,它減少了記憶體使用量並顯著縮短了啟動時間。

GraalVM Native Images 非常適合基於容器的部署和函式即服務平臺,它需要提前處理才能透過靜態程式碼分析建立可執行檔案。結果是特定於平臺的獨立可執行檔案,執行時不需要 JVM。

由於 GraalVM 不能直接感知 Java 程式碼中的動態元素,例如反射、資源、序列化和動態代理,因此我們需要為 GraalVM 提供有關這些元素的一些資訊。另一方面,Spring Boot 應用程式是動態的,配置在執行時執行。

Spring AOT(Ahead-of-Time)處理是 Spring 框架提供的功能,可以對 Spring 應用程式進行改造,使其更加相容 GraalVM。

Spring AOT 在構建時執行提前處理,並生成額外資產,如 Java 程式碼、位元組碼和 GraalVM JSON 提示檔案,幫助 GraalVM 進行提前編譯。

為此,我們需要在 Spring Boot 專案中使用 GraalVM 構建工具外掛:

<plugin>
 <groupId>org.graalvm.buildtools</groupId>
 <artifactId>native-maven-plugin</artifactId>
</plugin>

然後,為了構建 GraalVM 本地映象,我們可以在啟用本地配置檔案的情況下執行 spring-boot:build-image 目標:
mvn -Pnative spring-boot:build-image

它將使用 Buildpacks 為我們建立一個 docker 映象。

要生成本機可執行檔案而不是 Docker 鏡,我們可以執行此命令(確保您的機器上安裝了 GraalVM 發行版):
mvn -Pnative native:compile

5- JVM 檢查點恢復功能(Project CRaC)
該功能從 3.2 版開始新增到 Spring Boot,由 JVM 提供,使執行中的 Java 應用程式能夠儲存其狀態(稱為 "檢查點"),然後在稍後時間恢復該狀態。Spring Boot 將此功能與其 ApplicationContext 生命週期整合,用於自動檢查點,只需新增 -Dspring.context.checkpoint=onRefresh 引數即可使用。

該功能可透過以下方式提高 Spring Boot 應用程式的效能:

  • 更快的啟動時間:為了提高效能,Spring Boot 應用程式可以透過儲存預熱的 JVM 狀態和跳過耗時的重啟初始化來進行最佳化。
  • 提高穩定性:透過從可靠的檢查點恢復 JVM 狀態並繞過初始化相關問題,增強 Spring Boot 應用程式的穩定性,從而獲得更流暢、更可靠的體驗。
  • 減少資源使用:透過重複使用檢查點的現有 JVM 資源和減少總體資源消耗,最佳化 Spring Boot 應用程式的資源使用。

要使用此功能,我們需要安裝支援 CRaC 的 JDK 版本,並使用 Spring Boot 3.2 或更高版本。

6- 類資料共享(CDS)
類資料共享(CDS)是 Java 虛擬機器(JVM)的一項功能,有助於減少 Java 應用程式的啟動時間和記憶體佔用。從 3.3 版開始,它被整合到了 Spring Boot 中。

CDS 功能包括兩個主要步驟:1-建立 CDS 歸檔檔案,在應用程式退出時建立包含應用程式類的歸檔檔案(.jsa 格式) 2-使用 CDS 歸檔檔案,將 .jsa 檔案載入到記憶體中。

CDS 可縮短 Spring Boot 應用程式的啟動時間,因為訪問共享歸檔檔案比在 JVM 啟動時載入類更快。這也是一種節省記憶體的解決方案,因為

同一主機上的共享存檔有一部分被對映為只讀,由多個 JVM 程序共享,共享存檔還包含 Java Hotspot VM 所用形式的類資料。

7- 為 Spring MVC 和以資料庫為中心的應用程式配置執行緒
Spring Boot 應用程式可以並行處理多個請求,而實現高吞吐量的關鍵因素是要有足夠的執行緒來處理請求。控制器層和資料庫訪問層是可能導致瓶頸並需要仔細配置的兩個重要層。

控制器層執行緒配置:
如果由於任何原因無法在 Spring MVC 應用程式中使用虛擬執行緒功能,那麼為控制器層正確配置執行緒池就非常重要。

由於 Spring MVC 應用程式是在 Tomcat、Jetty 或 Undertow 等 servlet 容器上執行的,因此我們需要知道 servlet 容器的特定配置鍵,以配置執行緒池。例如,對於 Tomcat,我們有兩個重要的執行緒配置鍵:

  • server.tomcat.threads.max:處理請求的最大工作執行緒數。
  • server.tomcat.threads.min-spare:保持存活的工作執行緒的最小數量,也等於啟動時建立的執行緒數量。

server:
  tomcat:
    connection-timeout: 2s
    keep-alive-timeout: 10s
    threads:
      max: 500
      min-spare: 100


根據您使用的 servlet 容器,還有更多配置可以幫助我們配置它以獲得更好的效能。例如,對於 Tomcat,有兩個超時相關配置(server.tomcat.connection-timeout 和 server.tomcat.keep-alive-timeout)可能需要調整,以提高效能。


資料庫訪問層執行緒配置:
由於 JDBC 是與資料庫通訊的面向連線的標準,因此使用連線池非常重要。Spring Boot 預設使用 HikariCP 作為連線池。與 servlet 容器類似,每個連線池庫都有自己的配置鍵來配置它,對於 HikariCP,連線池最重要的配置是

  • spring.datasource.hikari.maximum-pool-size:池中資料庫連線的最大數量。
  • spring.datasource.hikari.minimum-idle:池中空閒資料庫連線的最小數量。

spring:
  datasource:
    username: deli
    password: p@ssword
    url: jdbc:postgresql:<font>//localhost:5432/sample_db<i>
    hikari:
      maximum-pool-size: 400
      minimum-idle: 100
      connection-timeout: 2000 
      

8- 使用快取策略
為 Spring Boot 應用程式選擇適當的快取策略可以大大提高其效能。如今,我們有許多微服務,資料分佈在它們之間。利用適當的快取策略,我們可以提高效能並減少多次往返。

根據應用程式的規模、資料訪問模式和效能要求,我們需要決定快取的兩個重要方面:

  • 1- 我們要快取什麼?我們想在快取中保留應用程式中的哪些資訊?
  • 2- 如何快取?我們使用哪種快取機制或方法?是使用本地快取、分散式快取,還是兩者兼用?我們想在快取中保留一段資料多長時間?

9- 採用彈性模式和最佳實踐
我認為這是一個非常重要的話題,尤其是現在,因為基於微服務架構的應用程式越來越多。

遵循斷路器、超時、回退和重試等彈性模式有助於 Spring Boot 應用程式更好地處理故障、有效分配資源並提供一致的效能,最終提高應用程式的整體效能。

Spring Boot 透過若干內建功能以及與 Resilience4j 等流行庫的整合來支援彈性模式。Spring Boot 透過自動配置所需的 Bean,並提供一種透過屬性或註解配置彈性模式的便捷方法,簡化了 Resilience4j 的整合。

Spring Cloud Circuit Breaker 為斷路器提供了一個抽象層,Resilience4j 可配置為在引擎蓋下使用。

@Service
public static class DemoControllerService {
 private RestTemplate rest;
 private CircuitBreakerFactory cbFactory;

 public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
  this.rest = rest;
  this.cbFactory = cbFactory;
 }

 public String slow() {
  return cbFactory.create(<font>"slow").run(
      () -> rest.getForObject(
"/slow", String.class), throwable -> "fallback"
    );
 }

}

10- 監控和剖析
透過將監控和剖析相結合,您可以深入瞭解 Spring Boot 應用程式的效能,並根據資料做出改進決策。

Spring Boot 自帶的許多庫和工具可用於此目的。Spring Boot Actuator 可以監控應用程式的執行狀況、收集指標並識別效能瓶頸。另一方面,從 Spring Boot 3.x 開始,使用 Spring 自動配置與 Micrometer 進行了很好的整合,這有助於我們獲得更好的指標和分散式跟蹤,最終實現更好的應用監控。

 

相關文章