SpringBoot3:應對C10K并發挑戰的優化指南

嘿,哥們!還在為服務的并發量上不去而頭疼嗎?用戶量一上來,CPU、內存就告急,接口響應慢得像蝸牛?別慌,今天我們就來盤一盤,怎么用最新的Spring Boot 3,把服務性能調教到極致,讓它從容應對C10K(即同時處理1萬個并發連接)甚至更高的挑戰。

目錄

一、為啥你的“開箱即用”Spring Boot扛不住?

二、Spring Boot 3的王牌:虛擬線程 (Virtual Threads)

三、光有虛擬線程還不夠:深入配置調優

3.1. Web服務器調優 (以Tomcat為例)

3.2. 數據庫連接池:最關鍵的瓶頸!

3.3. JVM調優

四、架構與代碼層面的神操作

4.1. 異步化你的CPU密集型任務

4.2. 緩存,緩存,還是緩存!

4.3. 終極奧義:WebFlux響應式編程

總結


一、為啥你的“開箱即用”Spring Boot扛不住?

首先得明白,Spring Boot默認的配置,是為了“通用”和“易用”,而不是為了“高性能”。它默認內嵌的Tomcat采用的是**“一個請求一個線程(Thread-Per-Request)”**的模型。

這模型在并發量小的時候很美好,簡單直接。但C10K一來,問題就暴露了:

  1. 線程是昂貴的:每個請求都得占用一個操作系統(OS)線程,而OS線程是很寶貴的資源,它需要消耗不少內存(通常是1MB左右),而且頻繁創建和銷毀的開銷也很大。

  2. I/O阻塞是性能殺手:大部分Web應用都是I/O密集型的,比如請求數據庫、調用其他微服務。在傳統模型下,一個請求在等待I/O時,對應的線程就被“阻塞”了,啥也干不了,只能干等著,白白占著茅坑。

當成千上萬的請求涌入,你的服務器很快就會因為線程數量達到上限而無法響應新的請求。

下面這張圖來直觀地理解這個窘境:

看到沒?粉色的線程都在“摸魚”,但資源卻一點沒少占。這就是瓶頸所在。

二、Spring Boot 3的王牌:虛擬線程 (Virtual Threads)

好消息是,Java 19帶來的Project Loom(并在Java 21成為正式功能),給了我們一個大殺器——虛擬線程。Spring Boot 3第一時間就集成了它。

啥是虛擬線程?簡單說:

它是一種由JVM自己管理的超輕量級線程。成千上萬個虛擬線程可以被映射到一小組OS平臺線程上運行。當虛擬線程遇到I/O阻塞時,它不會霸占平臺線程,而是會被“卸載”,讓平臺線程去執行其他任務。

這簡直就是為I/O密集型應用量身定做的!

在Spring Boot 3里啟用虛擬線程,簡單到令人發指,只需要在application.properties里加一行配置:

# 就這一行,你的Tomcat就開始用虛擬線程處理請求了
spring.threads.virtual.enabled=true

開啟后,整個模型就變成了這樣:

現在,就算有1萬個請求在等待數據庫返回,也只會占用極少的平臺線程,服務器的吞吐量瞬間就上去了。

三、光有虛擬線程還不夠:深入配置調優

別高興得太早,以為開了虛擬線程就萬事大吉了。真實的系統是個木桶,性能取決于最短的那塊板。下面我們就來一個個地加固這些木板。

3.1. Web服務器調優 (以Tomcat為例)

即便用了虛擬線程,Tomcat的一些核心參數還是需要我們去關注。

# application.yml
server:tomcat:# 最大連接數。這是服務器愿意接受的總連接數。對于C10K,這個值必須調大。max-connections: 12000 # 等待隊列長度。當所有線程都在忙時,新來的連接會在這里排隊。accept-count: 2000threads:# 雖然用了虛擬線程,但平臺線程池還是存在的,用于處理一些內部任務。# 這個值不需要很大,保持默認或根據CPU核心數設置即可。max: 200 # 這個是平臺線程數,不是虛擬線程數

3.2. 數據庫連接池:最關鍵的瓶頸!

這是最最最重要的一環!你的應用能創建1萬個虛擬線程,但你的數據庫能同時處理1萬個連接嗎?顯然不能。數據庫連接是昂貴的物理資源。

所以,千萬不要把連接池大小設置成10000!

HikariCP是Spring Boot默認的連接池,性能極佳。對于虛擬線程,它的配置哲學需要改變:

# application.yml
spring:datasource:hikari:# 這是關鍵!連接池大小不需要很大。一個經驗法則是 (CPU核心數 * 2) + 1。# 為什么?因為虛擬線程的哲學是“快速借用,快速歸還”。# 只要你的SQL執行夠快,小連接池也能服務大量請求。maximum-pool-size: 20# 最小空閑連接數,可以和最大值設成一樣,避免高峰期動態創建連接的開銷。minimum-idle: 20# 連接超時時間。如果連接池滿了,一個請求最多等多久。可以設短一點,快速失敗。connection-timeout: 2000 # 2秒# 最大生命周期。一個連接在池里活多久,避免因網絡問題產生死連接。max-lifetime: 600000 # 10分鐘

核心思想:用一個小的、高效的連接池,配合執行飛快的SQL,讓每個虛擬線程拿到連接后,迅速完成數據庫操作并釋放連接,從而實現高周轉率。你的優化重點應該放在減少SQL執行時間上。

3.3. JVM調優

對于C10K,JVM參數也得跟上。

# 啟動腳本里的JAVA_OPTS
-Xms4g -Xmx4g # 堆內存初始值和最大值設成一樣,避免GC時動態調整大小帶來性能抖動
-XX:+UseG1GC # 使用G1垃圾收集器,在響應時間和吞吐量之間有很好的平衡
-XX:MaxGCPauseMillis=200 # 期望的最大GC停頓時間
-Djava.security.egd=file:/dev/./urandom # 解決Tomcat啟動慢的問題

四、架構與代碼層面的神操作

配置拉滿了,代碼層面也不能拖后腿。

4.1. 異步化你的CPU密集型任務

虛擬線程能解決I/O阻塞,但如果你的代碼里有某個計算任務需要消耗大量CPU(比如復雜的加密、圖像處理),它還是會霸占著平臺線程不放,影響其他虛擬線程。

怎么辦?把這種CPU密集型任務扔到專門的線程池里去異步執行。

@Service
public class MyService {// 創建一個專門用于CPU密集型任務的線程池private final ExecutorService cpuBoundExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());public String handleRequest(String data) {// ... 一些I/O操作,可以充分享受虛擬線程的好處// someIoOperation(); // 現在,遇到一個CPU密集型任務CompletableFuture<String> cpuTask = CompletableFuture.supplyAsync(() -> {// 在專門的線程池里執行這個耗時計算return performComplexCalculation(data);}, cpuBoundExecutor);// 主虛擬線程可以繼續做別的事,或者等待結果try {return cpuTask.get(); // 等待異步任務完成} catch (InterruptedException | ExecutionException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}}private String performComplexCalculation(String data) {// 模擬一個非常耗CPU的操作// ...return "calculated_" + data;}
}

4.2. 緩存,緩存,還是緩存!

應對高并發,最簡單粗暴有效的方法就是減少對下游(尤其是數據庫)的直接訪問

  • 本地緩存(Caffeine):對于不常變化的數據,用本地緩存頂一下,連網絡I/O都省了。

  • 分布式緩存(Redis):多實例共享數據,減輕數據庫壓力。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;@Service
public class ProductService {// 加上這個注解,方法的結果就會被緩存。// 下次用相同的參數調用,直接從緩存返回,根本不執行方法體。@Cacheable(value = "products", key = "#id")public Product getProductById(String id) {// ... 這里是查詢數據庫的慢操作System.out.println("正在從數據庫查詢產品: " + id);return findProductInDB(id);}private Product findProductInDB(String id) {// 模擬DB查詢try {Thread.sleep(500); // 模擬慢查詢} catch (InterruptedException e) {}return new Product(id, "My Awesome Product");}
}

4.3. 終極奧義:WebFlux響應式編程

如果你的業務邏輯可以被描述為一系列事件流,并且你追求的是極致的資源利用率和最低的延遲,那么可以考慮Spring WebFlux。

WebFlux是完全基于事件驅動和非阻塞的,但學習曲線也更陡峭。它和虛擬線程是解決并發問題的兩種不同思路。

  • 虛擬線程:用大家熟悉的同步阻塞寫法,達到異步非阻塞的效果,遷移成本低。

  • WebFlux:需要用響應式API(Mono/Flux)重構代碼,心智負擔重,但性能天花板更高。

對于大部分現有項目,優先選擇虛擬線程進行優化,性價比最高。

?

總結

好了,哥們,一口氣說了這么多,我們來捋一捋。要讓你的Spring Boot 3應用在C10K下活下來并活得滋潤,你需要一套組合拳:

  1. 開啟虛擬線程:這是最核心的一步,解決了I/O阻塞的根本問題。(spring.threads.virtual.enabled=true)

  2. 壓榨數據庫連接池:用小而快的連接池,配合高效SQL,實現高周轉。

  3. 調優Web服務器和JVM:把基礎打牢,別讓它們拖后腿。

  4. 代碼層面優化:異步化CPU密集任務,善用緩存。

  5. 畫個圖總結一下:

性能優化沒有銀彈。它是一個系統工程,需要你從上到下,從配置到代碼,全面地進行分析和調整。

希望這篇能幫你在下一次性能挑戰中,成為那個最靚的仔!開干吧!

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

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

相關文章

響應式編程入門教程第三節:ReactiveCommand 與 UI 交互

響應式編程入門教程第一節&#xff1a;揭秘 UniRx 核心 - ReactiveProperty - 讓你的數據動起來&#xff01; 響應式編程入門教程第二節&#xff1a;構建 ObservableProperty&#xff1c;T&#xff1e; — 封裝 ReactiveProperty 的高級用法 響應式編程入門教程第三節&#x…

500+技術棧覆蓋:Web測試平臺TestComplete的對象識別技術解析

在用戶界面&#xff08;UI&#xff09;測試領域&#xff0c;傳統的測試工具往往依賴于XPath或CSS選擇器來定位頁面元素。然而&#xff0c;在面對動態變化的界面、多語言支持或是跨越多種技術框架的應用時&#xff0c;這些傳統方法常導致腳本失效&#xff0c;增加了維護成本。 …

研究人員利用提示注入漏洞繞過Meta的Llama防火墻防護

Trendyol應用安全團隊發現了一系列繞過技術&#xff0c;使得Meta的Llama防火墻在面對復雜的提示注入攻擊時防護失效。這一發現引發了人們對現有大語言模型&#xff08;LLM&#xff09;安全措施準備情況的擔憂&#xff0c;并凸顯出在企業日益將大語言模型嵌入工作流程時&#xf…

Shell 腳本系統學習 · 第5篇:多命令順序執行的三種方式詳解(`;`、``、`||`)

在日常的 Linux 運維與腳本編寫中&#xff0c;我們經常需要依次執行多條命令。本篇將帶你徹底搞懂三種命令順序執行方式&#xff1a;;、&& 和 ||&#xff0c;并通過實用示例掌握它們的區別與應用場景。一、為什么要了解多命令執行方式&#xff1f; 在實際運維或腳本編寫…

K8s存儲系統(通俗易懂版)

Kubernetes中存儲中有四個重要的概念&#xff1a;Volume、PersistentVolume PV、PersistentVolumeClaim PVC、StorageClass一、存儲系統核心概念Volume&#xff08;卷&#xff09;定義&#xff1a;Kubernetes 中最基礎的存儲單元&#xff0c;用于將外部存儲掛載到 Pod 中的容器…

小白學Python,標準庫篇——隨機庫、正則表達式庫

一、隨機庫1.隨機生成數值在random庫中可以隨機生成數值的方法有uniform()、random()、randint()、randrange()等。&#xff08;1&#xff09;uniform()方法uniform(參數1, 參數2)方法用于生成參數1到參數2之間的隨機小數&#xff0c;其中參數的類型都為數值類型。示例代碼&…

Qt窗口:菜單欄

目錄 一、窗口預覽 二、菜單欄 快捷鍵 子菜單 分割線 圖標 內存泄露 一、窗口預覽 在前面幾篇文章中&#xff0c;或者說&#xff0c;Qt初學階段&#xff0c;接觸到的都是QWidget&#xff0c;QWidget指控件&#xff0c;往往作為一個窗口的一部分出現。所謂的窗口&#x…

STM32裸機開發(中斷,輪詢,狀態機)與freeRTOS

裸機&#xff1a;沒有操作系統&#xff0c;程序是單流程的&#xff08;比如一個大循環里依次執行各個功能&#xff0c;或者用中斷嵌套處理事件&#xff09;。優點是資源占用極少&#xff08;幾乎不占 RAM/Flash&#xff09;、執行流程直觀&#xff1b;但復雜項目里&#xff0c;…

電腦上如何查看WiFi密碼

打開控制面板>點擊網絡和Internet在查看網絡和共享中心找到網絡狀態和任務點擊進去點擊連接的WLAN在WLAN狀態中點擊無線屬性在無線網絡屬性中點擊安全&#xff0c;點擊顯示字符&#xff08;H&#xff09;就可以顯示密碼了

文心一言4.5企業級部署實戰:多模態能力與Docker容器化測評

隨著大語言模型在企業服務中的應用日益廣泛&#xff0c;如何選擇一款既能滿足多模態創作需求&#xff0c;又具備良好企業級適配性的AI模型成為了關鍵問題。文心一言4.5作為百度最新開源的大模型&#xff0c;不僅在傳統的文本處理上表現出色&#xff0c;更是在多模態理解和企業級…

VUE Promise基礎語法

目錄 異步和同步 異步的問題 new Promise語法 promise的狀態 promise.then() Promise.resolve() Promise.reject() Promise.all() Promise.race() Promise.catch() Promise.finally() 異步和同步 同步模式下&#xff0c;代碼按順序執行&#xff0c;前一條執行完畢后…

用TensorFlow進行邏輯回歸(六)

import tensorflow as tfimport numpy as npfrom tensorflow.keras.datasets import mnistimport time# MNIST數據集參數num_classes 10 # 數字0到9, 10類num_features 784 # 28*28# 訓練參數learning_rate 0.01training_steps 1000batch_size 256display_step 50# 預處…

【HTTP版本演變】

在瀏覽器中輸入URL并按回車之后會發生什么1. 輸入URL并解析輸入URL后&#xff0c;瀏覽器會解析出協議、主機、端口、路徑等信息&#xff0c;并構造一個HTTP請求&#xff08;瀏覽器會根據請求頭判斷是否又HTTP緩存&#xff0c;并根據是否有緩存決定從服務器獲取資源還是使用緩存…

Android 16系統源碼_窗口動畫(一)窗口過渡動畫層級圖分析

一 窗口過渡動畫 1.1 案例效果圖1.2 案例源碼 1.2.1 添加權限 (AndroidManifest.xml) <!-- 系統懸浮窗權限&#xff08;Android 6.0需動態請求&#xff09; --> <uses-permission android:name"android.permission.SYSTEM_ALERT_WINDOW" />1.2.2 窗口顯示…

騰訊云WAF域名分級防護實戰筆記

基于業務風險等級、合規要求及騰訊云最佳實踐&#xff0c;提供可直接落地的配置方案&#xff0c;供學習借鑒&#xff1a;一、域名分級與防護原則1. ?域名分級清單&#xff08;核心資產&#xff09;???主域名??業務類型??風險等級??合規要求??防護等級?example.com…

1. 請說出你知道的水平垂直居中的方法

總結 容器 flex 布局&#xff0c;jsutify-content: center; align-items: center;容器 flex 布局&#xff0c;子項 margin: auto;容器 relative 布局&#xff0c;子項 absolute 布局&#xff0c;left: 50%; top: 50%; transform: translate(-50%, -50%);子項 absolute 布局&…

VS Code `launch.json` 完整配置指南:參數詳解 + 配置實例

文章目錄&#x1f4e6; 一、基本結構&#x1f50d; 二、單個配置項詳解示例配置&#xff1a;&#x1f9e9; 三、字段說明與可選值&#x1f4c1; 四、常用變量&#xff08;宏替換&#xff09;&#x1f6e0;? 五、常見配置實例1?? 調試當前打開的 .py 文件2?? 調試 Jupyter …

使用瀏覽器inspect調試wx小程序

edge://inspect/#devices調試wx小程序 背景&#xff1a; 在開發混合項目的過程中&#xff0c;常常需要在app環境排查問題&#xff0c;接口可以使用fiddler等工具來抓包&#xff0c;但是js錯誤就不好抓包了&#xff0c;這里介紹一種調試工具-瀏覽器。 調試過程 首先電腦打開edg…

【論文閱讀】-《Simple Black-box Adversarial Attacks》

簡單黑盒對抗攻擊 Chuan Guo Jacob R. Gardner Yurong You Andrew Gordon Wilson Kilian Q. Weinberger 摘要 我們提出了一種在黑盒&#xff08;black-box&#xff09;場景下構建對抗樣本&#xff08;adversarial images&#xff09;的極其簡單的方法。與白盒&#xff08;…

基于ASP.NET+SQL Server實現(Web)企業進銷存管理系統

企業進銷存管理系統的設計和實現一、摘要進銷存管理是現代企業生產經營中的重要環節&#xff0c;是完成企業資源配置的重要管理工作&#xff0c;對企業生產經營效率的最大化發揮著重要作用。本文以我國中小企業的進銷存管理為研究對象&#xff0c;描述了企業進銷存管理系統從需…