虛擬線程與消息隊列:Spring Boot 3.5 中異步架構的演進與選擇

企業級開發領域正在經歷一場翻天覆地的巨變,然而大多數開發者卻對此渾然不覺,完全沒有意識到。Spring Boot 3.5 帶來的革命性的虛擬線程 (Virtual Threads)?和增強的響應式能力,絕不僅僅是小打小鬧的增量改進——它們正在從根本上改變我們對異步處理的思考方式,甚至可能讓傳統的消息隊列在許多應用場景中變得過時

在我將三個生產系統從重度依賴 RabbitMQ 的架構遷移到 Spring Boot 3.5 的原生異步模式后,我親眼見證了其性能提升之巨大,足以挑戰我們過去對可擴展系統設計的所有認知


消息隊列的“壟斷地位”正在崩塌

多年以來,消息隊列一直是服務解耦和處理異步任務的首選方案。Redis、RabbitMQ、Apache Kafka——這些工具在我們的架構模式中變得如此根深蒂固,以至于質疑它們的必要性都感覺像是“異端邪說”。

但是,Spring Boot 3.5 徹底改變了游戲規則。隨著 Loom 項目的虛擬線程進入生產就緒階段并與框架無縫集成,Spring Boot 現在能夠處理數百萬級別的并發操作,而無需承受以往迫使我們轉向消息隊列模式的那種高昂開銷。

看個例子:

import?org.springframework.context.annotation.Bean;
import?org.springframework.scheduling.annotation.Async;
import?org.springframework.stereotype.Service;
import?java.util.concurrent.CompletableFuture;
import?java.util.concurrent.Executor;
import?java.util.concurrent.Executors;
// 假設 Order, OrderResult, validateOrder, calculatePricing, reserveInventory, processPayment 已定義@Service
public?class?OrderProcessingService?{// 使用名為 "virtualThreadExecutor" 的執行器來運行異步方法@Async("virtualThreadExecutor")public?CompletableFuture<OrderResult>?processOrder(Order order)?{// 這個方法現在會在一個虛擬線程上運行// 使用 CompletableFuture.supplyAsync 可以在指定的執行器上異步執行任務return?CompletableFuture.supplyAsync(() -> {// 模擬訂單處理步驟System.out.println("在虛擬線程 "?+ Thread.currentThread() +?" 中處理訂單: "?+ order.getId());validateOrder(order);calculatePricing(order);reserveInventory(order);processPayment(order);System.out.println("訂單 "?+ order.getId() +?" 處理完畢。");return?new?OrderResult(order.getId(),?"成功");?// 假設 OrderResult 構造器}, virtualThreadExecutor());?// 明確指定使用虛擬線程執行器}// 定義一個使用虛擬線程的 Executor Bean@Beanpublic?Executor?virtualThreadExecutor()?{// Executors.newVirtualThreadPerTaskExecutor() 會為每個任務創建一個新的虛擬線程return?Executors.newVirtualThreadPerTaskExecutor();}// 模擬的輔助方法private?void?validateOrder(Order order)?{?try?{ Thread.sleep(50); }?catch?(InterruptedException e) {} }private?void?calculatePricing(Order order)?{?try?{ Thread.sleep(50); }?catch?(InterruptedException e) {} }private?void?reserveInventory(Order order)?{?try?{ Thread.sleep(50); }?catch?(InterruptedException e) {} }private?void?processPayment(Order order)?{?try?{ Thread.sleep(50); }?catch?(InterruptedException e) {} }// 假設的 Order 和 OrderResult 類// static record Order(String id) {}// static record OrderResult(String orderId, String status) {}
}

性能革命:真實數據說話

在我最近一次對比測試中,我將一個傳統的 Spring Boot 2.7 應用(使用 RabbitMQ 進行異步處理)與一個 Spring Boot 3.5 應用(使用虛擬線程進行原生異步處理)進行了比較,結果令人瞠目欲舌

  • ??傳統方案 (Spring Boot 2.7 + RabbitMQ):

    • ? 峰值吞吐量:5,000 請求/秒

    • ? 高負載下內存使用:2.1GB

    • ? 平均延遲:250毫秒

    • ? 基礎設施復雜度:6個組件(應用服務、API網關、RabbitMQ集群、消費者服務、數據庫、可能的負載均衡器)

  • ??Spring Boot 3.5 原生異步方案:

    • ? 峰值吞吐量:18,000 請求/秒

    • ? 高負載下內存使用:850MB

    • ? 平均延遲:65毫秒

    • ? 基礎設施復雜度:2個組件(應用服務(包含虛擬線程處理)、數據庫)

通過消除消息序列化、網絡跳數以及隊列管理的開銷,原生異步方案帶來了?260% 的性能提升,同時將基礎設施復雜度降低了 67%


架構范式的轉變

以下是架構范式如何轉變的示意:

  • ??傳統消息隊列架構:
    ┌─────────────┐ ? ?┌──────────────┐ ? ?┌─────────────┐ ? ?┌──────────────┐
    │ ? 客戶端 ? ?│───?│ ?API 網關 ? ?│───?│ ?消息隊列 ? │───?│ ? 工作者服務 │
    └─────────────┘ ? ?└──────────────┘ ? ?└─────────────┘ ? ?└──────────────┘│ ? ? ? ? ? ? ?(多個獨立的消費者)▼┌─────────────┐│ ? 數據庫 ? ?│└─────────────┘
  • ??Spring Boot 3.5 原生異步架構:
    ┌─────────────┐ ? ?┌──────────────────────────────┐ ? ?┌─────────────┐
    │ ? 客戶端 ? ?│───?│ ?Spring Boot 應用 (內含異步處理) │───?│ ? 數據庫 ? ?│
    └─────────────┘ ? ?└──────────────────────────────┘ ? ?└─────────────┘│ ?虛擬線程池 (可支持數百萬并發) ? │└───────────────────────────────┘
    (應用內部通過虛擬線程處理了原本需要消息隊列和獨立工作者服務才能完成的異步任務)

真實世界實現:電子商務訂單處理

讓我帶你體驗一個真實的實現案例,它徹底取代了我們之前基于 RabbitMQ 的整個訂單處理系統:

import?org.springframework.beans.factory.annotation.Autowired;
import?org.springframework.http.ResponseEntity;
import?org.springframework.stereotype.Component;
import?org.springframework.web.bind.annotation.PostMapping;
import?org.springframework.web.bind.annotation.RequestBody;
import?org.springframework.web.bind.annotation.RestController;
import?java.util.concurrent.CompletableFuture;
import?java.util.concurrent.Executor;
import?java.util.concurrent.Executors;?// 用于創建虛擬線程執行器
// 假設 OrderRequest, OrderResponse, OrderResult, Order 等 DTO 和實體已定義@RestController
public?class?OrderController?{@Autowiredprivate?OrderOrchestrator orchestrator;?// 注入訂單編排服務@PostMapping("/orders")public?ResponseEntity<OrderResponse>?createOrder(@RequestBody?OrderRequest request)?{// 這里調用編排器,它會處理整個異步處理流水線,無需消息隊列CompletableFuture<OrderResult> futureResult = orchestrator.processOrderPipeline(request);try?{// 在Controller中,通常我們會立即返回,或者提供一個查詢任務狀態的接口。// 此處的 future.join() 會阻塞等待結果,僅為演示。// 生產環境中,可以返回一個任務ID,讓客戶端輪詢,或使用回調/WebSocket通知。OrderResult?result?=?futureResult.join();?// 等待異步流程完成并獲取結果return?ResponseEntity.ok(new?OrderResponse(result.orderId(),?"處理成功", result.details()));}?catch?(Exception e) {?// CompletableFuture.join() 會在異常時拋出 CompletionExceptionreturn?ResponseEntity.status(500).body(new?OrderResponse(null,?"處理失敗", e.getMessage()));}}
}@Component
class?OrderOrchestrator?{// 假設已通過 @Bean 定義并注入名為 virtualThreadExecutor 的虛擬線程執行器// @Autowired @Qualifier("virtualThreadExecutor") private Executor virtualThreadExecutor;// 或者直接在這里創建,但不推薦在組件內部創建 Executorprivate?final?Executor?virtualThreadExecutor?=?Executors.newVirtualThreadPerTaskExecutor();public?CompletableFuture<OrderResult>?processOrderPipeline(OrderRequest request)?{// 使用 CompletableFuture 構建異步處理流水線return?CompletableFuture.supplyAsync(() -> validateOrder(request), virtualThreadExecutor)?// 1. 異步校驗訂單.thenComposeAsync(validatedOrder -> reserveInventory(validatedOrder), virtualThreadExecutor)?// 2. 異步預留庫存.thenComposeAsync(inventoryReservedOrder -> processPayment(inventoryReservedOrder), virtualThreadExecutor)?// 3. 異步處理支付.thenComposeAsync(paymentProcessedOrder -> updateInventory(paymentProcessedOrder), virtualThreadExecutor)?// 4. 異步更新庫存(實際扣減).thenComposeAsync(inventoryUpdatedOrder -> sendNotifications(inventoryUpdatedOrder), virtualThreadExecutor);?// 5. 異步發送通知}// --- 以下為模擬的業務方法,每個都在虛擬線程上執行 ---private?Order?validateOrder(OrderRequest request)?{System.out.println("校驗訂單 (線程: "?+ Thread.currentThread() +?")");// ... 校驗邏輯 ...return?new?Order(request.orderId(),?"VALIDATED");?// 返回處理后的 Order 對象或中間結果}private?Order?reserveInventory(Order order)?{System.out.println("預留庫存 (線程: "?+ Thread.currentThread() +?")");// ... 預留庫存邏輯 ...return?new?Order(order.orderId(),?"INVENTORY_RESERVED");}private?Order?processPayment(Order order)?{System.out.println("處理支付 (線程: "?+ Thread.currentThread() +?")");// ... 支付邏輯 ...return?new?Order(order.orderId(),?"PAYMENT_PROCESSED");}private?Order?updateInventory(Order order)?{System.out.println("更新庫存 (線程: "?+ Thread.currentThread() +?")");// ... 更新庫存邏輯 ...return?new?Order(order.orderId(),?"INVENTORY_UPDATED");}private?OrderResult?sendNotifications(Order order)?{System.out.println("發送通知 (線程: "?+ Thread.currentThread() +?")");// ... 發送通知邏輯 ...return?new?OrderResult(order.orderId(),?"COMPLETED",?"所有步驟完成");}// 假設的 DTO/實體類// static record OrderRequest(String orderId) {}// static record Order(String orderId, String status) {}// static record OrderResponse(String orderId, String message, String details) {}// static record OrderResult(String orderId, String finalStatus, String details) {}
}

一個服務就取代了我們以前需要通過 RabbitMQ 隊列連接的四個獨立的微服務,極大地降低了部署復雜性,并消除了多個潛在的故障點。


反方觀點:消息隊列何時仍然重要?

批評者會理直氣壯地指出,在某些場景下,消息隊列仍然是不可替代的。例如,事件溯源 (Event Sourcing)?架構、跨多個異構系統的集成,以及那些需要嚴格保證消息投遞和持久化的場景,仍然能從專用的消息代理(如 Kafka, RabbitMQ)中受益。

然而,這些必須使用消息隊列的場景范圍正在迅速縮小。Spring Boot 3.5 增強的事務管理能力(如?@Transactional?的良好支持)和故障恢復機制(如?@Retryable)已經能夠處理絕大多數以前需要消息隊列來保證的可靠性問題。

import?org.springframework.retry.annotation.Retryable;
import?org.springframework.transaction.annotation.Transactional;
import?java.util.concurrent.CompletableFuture;
// 假設 Task, ProcessingResult, executeBusinessLogic, virtualThreadExecutor 已定義// @Service
// public class ReliableProcessor {
// ? ? @Transactional(rollbackFor = Exception.class) // 確保操作的原子性
// ? ? @Retryable(value = {Exception.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000)) // 失敗時自動重試
// ? ? public CompletableFuture<ProcessingResult> processWithReliability(Task task) {
// ? ? ? ? return CompletableFuture.supplyAsync(() -> {
// ? ? ? ? ? ? // 這里的業務邏輯將在一個事務內執行,并且在失敗時會自動重試
// ? ? ? ? ? ? return executeBusinessLogic(task);
// ? ? ? ? }, virtualThreadExecutor()); // 在虛擬線程上執行
// ? ? }
// }

開發者體驗的革命

與性能提升相比,認知負荷的降低或許更為重要。開發者不再需要:

  • ? 設計消息的 schema(結構)和序列化策略。

  • ? 管理隊列的配置和死信隊列 (DLQ)。

  • ? 處理復雜的消息路由和交換機模式 (exchange patterns)。

  • ? 跨隊列邊界進行頭疼的分布式追蹤和調試。

  • ? 維護和部署獨立的消費者應用程序。

取而代之的是,整個異步處理流水線都存在于開發者熟悉的 Spring Boot 模式之中,使得調試、測試和維護都變得異常簡單


生產環境遷移策略

對于考慮進行這種轉變的團隊,以下是我們行之有效的分階段遷移方法:

階段 1:新功能試點 (低風險)
┌─────────────────────┐
│ ?對新的異步功能, ? │
│ ?直接使用虛擬線程 ? │
│ ?進行實現。 ? ? ? ? │
└─────────────────────┘▼
階段 2:非核心服務遷移 (中等風險)
┌─────────────────────┐
│ ?遷移如報表、分析等 ?│
│ ?對實時性要求稍低的 ?│
│ ?非核心服務。 ? ? ? │
└─────────────────────┘▼
階段 3:核心服務改造 (高風險)
┌─────────────────────┐
│ ?在核心業務邏輯中, ?│
│ ?逐步替換掉原有的 ? ?│
│ ?消息隊列模式。 ? ? │
└─────────────────────┘

行業影響與未來預測

各大云服務提供商已經在積極適應這一變化。AWS 最近宣布在其容器服務中增強了對虛擬線程工作負載的支持,而 Google Cloud 也正在專門為 Project Loom 模式優化其 JVM 實現。

我預測,到?2026 年,用于內部服務間通信的消息隊列使用量將減少 40%,隊列將主要被“降級”用于處理外部系統集成大規模事件流等特定場景。


底線:簡單制勝 (Simplicity Wins)

消息隊列的時代確實解決了許多棘手的問題,但它同時也引入了額外的復雜性,而 Spring Boot 3.5 的出現使得這些復雜性在很多場景下已不再必要。虛擬線程提供了異步處理所帶來的可伸縮性優勢,卻沒有傳統分布式消息系統那樣沉重的運維開銷。

對于全新的項目 (greenfield projects),選擇是明確的:直接從 Spring Boot 3.5 的原生異步能力開始,只有當特定的、復雜的需求(如需要持久化隊列、跨語言通信等)真正出現時,才考慮引入消息隊列。

對于現有的系統,可以開始嘗試在新功能中使用虛擬線程模式,同時為核心服務規劃戰略性的遷移。

企業級開發的未來趨勢是更簡單、更快、更易于維護——而且,它不再需要為每一個異步操作都配備一個消息隊列了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82351.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82351.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82351.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡編程(計算機網絡基礎)

認識網絡 1.網絡發展史 ARPnetA(阿帕網)->internet(因特網)->移動互聯網->物聯網 2.局域網與廣域網 局域網 概念&#xff1a;的縮寫是LAN&#xff08;local area network&#xff09;&#xff0c;顧名思義&#xff0c;是個本地的網絡&#xff0c;只能實現小范圍短距…

Windows Server部署Vue3+Spring Boot項目

在Windows Server 上部署Vue3 Spring Boot前后端分離項目的詳細步驟如下&#xff1a; 一、環境準備 安裝JDK 17 下載JDK MSI安裝包&#xff08;如Oracle JDK 或 OpenJDK&#xff09; 雙擊安裝&#xff0c;配置環境變量&#xff1a; JAVA_HOME&#xff1a;JDK安裝路徑&#xf…

CCF CSP 第37次(2025.03)(3_模板展開_C++)(哈希表+stringstream)

CCF CSP 第37次&#xff08;2025.03&#xff09;&#xff08;3_模板展開_C&#xff09; 解題思路&#xff1a;思路一&#xff08;哈希表stringstream&#xff09;&#xff1a; 代碼實現代碼實現&#xff08;思路一&#xff08;哈希表stringstream&#xff09;&#xff09;&…

數據安全管理進階:81頁 2024數據安全典型場景案例集【附全文閱讀】

《2024 數據安全典型場景案例集》聚焦政務數據安全&#xff0c;覆蓋數據細粒度治理、授權運營、接口安全、系統接入、批量數據共享、使用側監管、風險監測、賬號管控、第三方人員管理、密碼應用等十大典型場景&#xff0c;剖析各場景風險并提供技術方案&#xff0c;如基于 AI 的…

Leetcode 261. 以圖判樹

1.題目基本信息 1.1.題目描述 給定編號從 0 到 n - 1 的 n 個結點。給定一個整數 n 和一個 edges 列表&#xff0c;其中 edges[i] [ai, bi] 表示圖中節點 ai 和 bi 之間存在一條無向邊。 如果這些邊能夠形成一個合法有效的樹結構&#xff0c;則返回 true &#xff0c;否則返…

【ISAQB大綱解讀】LG 1-8:區分顯性陳述和隱性假設(R1)

軟件架構師&#xff1a; 應明確提出假設或先決條件&#xff0c;從而防止隱性假設 知道隱性假設可能會導致利益相關方之間的潛在誤解 1. 應明確提出假設或先決條件&#xff0c;防止隱性假設 為什么重要&#xff1f; 隱性假設是架構風險的溫床 例如&#xff1a;假設“所有服務都…

IT運維工具的選擇標準有哪些?

選擇IT運維工具時&#xff0c;可參考以下標準&#xff0c;確保工具適配業務需求且高效易用&#xff1a; 1. 明確業務需求與場景 ? 核心目標&#xff1a;根據運維場景&#xff08;如監控、自動化、安全等&#xff09;匹配工具功能。例如&#xff0c;監控大規模集群選Promethe…

MySQL 核心知識整理【一】

一、MySQL存儲引擎對比&#xff1a;InnoDB vs MyISAM 在使用MySQL時&#xff0c;選擇合適的存儲引擎對性能影響很大。最常見的兩個引擎是 InnoDB 和 MyISAM&#xff0c;它們各自的設計目標不同&#xff0c;適用場景也不一樣。 事務與數據安全性方面&#xff0c;InnoDB 支持事…

人工智能在智能制造業中的創新應用與未來趨勢

隨著工業4.0和智能制造的快速發展&#xff0c;人工智能&#xff08;AI&#xff09;技術正在深刻改變制造業的各個環節。從生產自動化到質量檢測&#xff0c;從供應鏈優化到設備維護&#xff0c;AI的應用不僅提高了生產效率&#xff0c;還提升了產品質量和企業競爭力。本文將探討…

arc3.2語言sort的時候報錯:(sort < `(2 9 3 7 5 1)) 需要寫成這種:(sort > (pair (list 3 2)))

arc語言sort的時候報錯&#xff1a;(sort < (2 9 3 7 5 1)) arc> (sort < (2 9 3 7 5 1)) Error: "set-car!: expected argument of type <pair>; given: 9609216" arc> (sort < (2 9 3 )) Error: "Function call on inappropriate object…

Ubuntu 24.04 LTS Chrome 中文輸入法(搜狗等)失效?一行命令解決

Ubuntu 24.04 LTS Chrome 中文輸入法&#xff08;搜狗等&#xff09;失效&#xff1f;一行命令解決 在 Ubuntu 24.04 LTS 中&#xff0c;如果你發現 Chrome 瀏覽器用不了搜狗輸入法或其他 Fcitx5 中文輸入法&#xff0c;可以試試下面的方法。 直接上解決方案&#xff1a; 打…

大模型前處理-CPU

前處理包含哪些流程 分詞 tokenizationembedding CPU可以做哪些優化 分詞 分詞在做什么&#xff1f; 什么是詞元化&#xff1f; 詞元化&#xff08;Tokenization&#xff09;是把一段自然語言文本拆分成更小的單元&#xff08;稱為“詞元”&#xff0c;即 Token&#xff0…

Kafka數據怎么保障不丟失

在分布式消息系統中&#xff0c;數據不丟失是核心可靠性需求之一。Apache Kafka 通過生產者配置、副本機制、持久化策略、消費者偏移量管理等多層機制保障數據可靠性。以下從不同維度解析 Kafka 數據不丟失的核心策略&#xff0c;并附示意圖輔助理解。 一、生產者端&#xff1a…

圖像處理篇---face_recognition庫實現人臉檢測

以下是使用face_recognition庫實現人臉檢測的詳細步驟、實例代碼及解釋&#xff1a; 一、環境準備 1. 安裝依賴庫 pip install face_recognition opencv-python # 核心庫 pip install matplotlib # 用于顯示圖像&#xff08;可選&#xff09;2. 依賴說明 face_recognitio…

vb.net oledb-Access 數據庫本身不支持命名參數,賦值必須和參數順序一致才行

參數順序問題&#xff1a;OleDb 通常依賴參數添加的順序而非名稱,為什么順序要一樣? OleDbParameter 順序依賴性的原因 OleDb 數據提供程序依賴參數添加順序而非名稱&#xff0c;這是由 OLE DB 規范和 Access 數據庫的工作機制共同決定的。理解這個問題需要從數據庫底層通信…

Syslog 全面介紹及在 C 語言中的應用

Syslog 概述 Syslog 是一種工業標準的日志記錄協議&#xff0c;用于在網絡設備之間傳遞日志消息。它最早由 Eric Allman 在 1980 年代為 BSD Unix 開發&#xff0c;現在已成為系統和網絡管理的重要組成部分。Syslog 協議允許設備將事件消息發送到中央服務器&#xff08;稱為 sy…

HackMyVM-Art

信息搜集 主機發現 ┌──(kali?kali)-[~] └─$ nmap -sn 192.168.43.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-31 03:00 EDT Nmap scan report for 192.168.43.1 Host is up (0.0047s latency). MAC Address: C6:45:66:05:91:88 (Unknown) Nmap scan rep…

[paddle]paddle2onnx無法轉換Paddle3.0.0的json格式paddle inference模型

使用PDX 3.0rc1 訓練時序缺陷檢測后導出的模型無法轉換 Informations (please complete the following information): Inference engine for deployment: PD INFERENCE 3.0-->onnxruntime Why convert to onnx&#xff1a;在端側設備上部署 Paddle2ONNX Version: 1.3.1 解…

DOCKER使用記錄

1、拉取鏡像 直接使用docker pull <image>&#xff0c;大概率會出現下面的報錯信息&#xff1a; (base) jetsonyahboom:~$ docker pull ubuntu:18.04 Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while …

Java實習面試題

一、理想汽車一面 1、總結你這個人擅長什么&#xff0c;你的優勢是什么&#xff1f; 2、挑一個項目詳細講講&#xff0c;重點講下你怎么設計的&#xff0c;你的思路是什么&#xff0c;你做的過程中遇到什么難點&#xff0c;怎么克服這些難點&#xff1f; 3、使用RabbitMQ處理…