讓 SpringBoot 飛起來(lái)!15條性能優(yōu)化秘籍,輕松應(yīng)對(duì)百萬(wàn)并發(fā)!
引言
為何提前暴露指標(biāo)與分析的重要性
在正式進(jìn)行性能優(yōu)化之前,必須先“看得到”系統(tǒng)運(yùn)行狀況:緩存命中率、數(shù)據(jù)庫(kù)連接池使用情況、響應(yīng)時(shí)長(zhǎng)分布、CPU/內(nèi)存消耗、垃圾回收停頓等。只有掌握真實(shí)數(shù)據(jù),才能有針對(duì)性地優(yōu)化;盲目調(diào)整往往事倍功半,甚至適得其反。
指標(biāo)暴露與監(jiān)控接入
Prometheus 集成
1.Maven 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>2.application.properties/application.yml 配置
management.endpoint.metrics.enabled=true
management.endpoint.prometheus.enabled=true
management.endpoints.web.exposure.include=health,info,prometheus,metrics
management.metrics.export.prometheus.enabled=true
management.endpoint.health.show-details=always
# 可根據(jù)需要開放其他端點(diǎn),如 httptrace、threaddump3.啟動(dòng)與訪問(wèn)
啟動(dòng)后,訪問(wèn) http://<host>:<port>/actuator/prometheus 可看到所有默認(rèn)與自定義指標(biāo)。
配置 Prometheus server 抓取該 endpoint,例如在 prometheus.yml:
scrape_configs:
- job_name: 'springboot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app-host:port']4.自定義業(yè)務(wù)指標(biāo)示例
@RestController
publicclassTestController{
privatefinal MeterRegistry registry;
publicTestController(MeterRegistry registry){
this.registry = registry;
}
@GetMapping("/test")
public String test(){
registry.counter("app_test_invocations", "from", "127.0.0.1", "method", "test").increment();
return"ok";
}
}在 Prometheus 中可見指標(biāo)如 app_test_invocations_total{from="127.0.0.1",method="test"} 5.0
圖片
對(duì)于緩存命中率,可在緩存攔截或 CacheManager 事件中注冊(cè) Counter/Gauge,例如:
Cache<Object, Object> cache = ...; // 若使用 Caffeine,可 attach 監(jiān)聽
// 當(dāng)命中時(shí) registry.counter("cache_hit", "cache", "myCache").increment();
// 當(dāng)未命中時(shí) registry.counter("cache_miss", "cache", "myCache").increment();5.Grafana 可視化與 AlertManager
在 Grafana 中配置 Prometheus 數(shù)據(jù)源,創(chuàng)建 Dashboard 展示:
- JVM 內(nèi)存、GC 停頓、線程數(shù)
- HTTP 請(qǐng)求速率、延遲分布(可借助
Histogram/Summary) - 緩存命中率:
hit/(hit+miss) - 數(shù)據(jù)庫(kù)連接池使用率:活躍連接數(shù) vs 最大連接數(shù)
AlertManager 配置告警規(guī)則,例如:
- 95% 延遲超過(guò)閾值
- GC 停頓時(shí)長(zhǎng)過(guò)長(zhǎng)
- 連接池耗盡告警
此部分可參考 Prometheus 與 Grafana 官方文檔,自行搭建實(shí)驗(yàn)環(huán)境。
圖片
性能剖析工具:火焰圖與 async-profiler
async-profiler 下載與使用
1.從 GitHub 下載 async-profiler release 包,解壓至服務(wù)器目錄,如 /opt/async-profiler。關(guān)注公眾號(hào):碼猿技術(shù)專欄,回復(fù)關(guān)鍵詞:1111 獲取阿里內(nèi)部Java性能調(diào)優(yōu)手冊(cè)!
2.啟動(dòng) SpringBoot 應(yīng)用時(shí),添加 javaagent 參數(shù):
java -agentpath:/opt/async-profiler/build/libasyncProfiler.so=start,svg,file=profile.svg -jar your-app.jar3.運(yùn)行一段業(yè)務(wù)場(chǎng)景(壓測(cè)或真實(shí)流量),然后停止進(jìn)程或通過(guò) async-profiler 提供的 CLI 停止采樣:
# 若不想重啟,可 attach 模式:
./profiler.sh -d 30 -f profile.svg <pid>4.查看生成的 profile.svg,用瀏覽器打開:
圖片
- 橫軸表示消耗的采樣比例,寬度越大表示更耗時(shí)的方法。
- 縱向?yàn)檎{(diào)用棧層級(jí)。
- 從最寬處逐層向下分析,找到熱點(diǎn)方法,結(jié)合源代碼定位優(yōu)化點(diǎn)。
結(jié)合 Flame 圖優(yōu)化示例
- 若熱點(diǎn)在某個(gè)慢方法,可查看方法內(nèi)部邏輯:是否存在不必要的循環(huán)、I/O 阻塞,或可并行優(yōu)化。
- 若熱點(diǎn)在序列化/反序列化,可考慮更高效的庫(kù)或減小返回對(duì)象結(jié)構(gòu)。
- 若大量時(shí)間在 GC,可結(jié)合 GC 日志分析堆配置是否合理。
HTTP 及 Web 層優(yōu)化
圖片
CDN 與靜態(tài)資源加速
- 將常用靜態(tài)資源(JS、CSS、圖片)托管于 CDN,減輕后端壓力;用戶訪問(wèn)時(shí)由地理就近節(jié)點(diǎn)提供。
- 對(duì)第三方庫(kù)可使用公共 CDN;自有資源可上傳到 CDN 或靜態(tài)文件服務(wù)器。
Cache-Control/Expires 在 Nginx 中配置示例
location ~* \.(ico|gif|jpg|jpeg|png|css|js)$ {
add_header Cache-Control "max-age=31536000, immutable";
}根據(jù)資源更新策略設(shè)置版本號(hào)或文件指紋,保證緩存命中又可及時(shí)更新。
減少域名數(shù)量
- 將靜態(tài)資源和 API 接口合理合并域名;避免過(guò)多不同子域?qū)е?DNS 查詢延遲。
- 可啟用 HTTP/2 時(shí),多路復(fù)用可減少域名依賴,但 HTTP/2 支持需服務(wù)器和客戶端皆啟用。
Gzip 及資源壓縮配置
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_http_version 1.1;
gzip_types text/plain application/javascript text/css application/json;- 確保對(duì)動(dòng)態(tài) JSON 接口開啟 gzip,減小響應(yīng)體體積。
- 對(duì)大型靜態(tài)文件可在構(gòu)建時(shí)先行壓縮(如 Brotli),結(jié)合 Nginx 支持。
Keep-Alive 配置
客戶端與 Nginx:
http {
keepalive_timeout 60s 60s;
keepalive_requests 10000;
}Nginx 與 SpringBoot 后端長(zhǎng)連接:
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
}SpringBoot/Tomcat 默認(rèn)支持 Keep-Alive;可通過(guò)自定義 Connector 調(diào)整超時(shí)。
SpringBoot 容器調(diào)優(yōu)
自定義嵌入式 Tomcat
如果項(xiàng)目并發(fā)量比較高,想要修改最大線程數(shù)、最大連接數(shù)等配置信息,可以通過(guò)自定義Web 容器的方式,代碼如下所示。
@SpringBootApplication(proxyBeanMethods = false)
publicclassAppimplementsWebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
publicstaticvoidmain(String[] args){
SpringApplication.run(App.class, args);
}
@Override
publicvoidcustomize(ConfigurableServletWebServerFactory factory){
if (factory instanceof TomcatServletWebServerFactory) {
TomcatServletWebServerFactory f = (TomcatServletWebServerFactory) factory;
f.setProtocol("org.apache.coyote.http11.Http11Nio2Protocol");
f.addConnectorCustomizers(c -> {
Http11NioProtocol protocol = (Http11NioProtocol) c.getProtocolHandler();
protocol.setMaxConnections(200);
protocol.setMaxThreads(200);
protocol.setConnectionTimeout(30000);
// protocol.setSelectorTimeout(3000); // NIO2 可選項(xiàng)
});
}
}
}設(shè)置協(xié)議為 NIO2 可在高并發(fā) I/O 場(chǎng)景下提升性能;需基準(zhǔn)測(cè)試驗(yàn)證。
setMaxThreads 和 setMaxConnections 值根據(jù)服務(wù)器硬件資源與業(yè)務(wù)并發(fā)調(diào)整,可在壓測(cè)環(huán)境多次嘗試并觀察響應(yīng)延遲、CPU 利用率、線程使用情況。
圖片
替換 Undertow
在 pom.xml 中排除 Tomcat 并引入 Undertow:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>- Undertow 線程模型和資源占用一般較輕;需要在業(yè)務(wù)場(chǎng)景中壓測(cè)對(duì)比。
- 注意部分 Tomcat 特有配置不適用,需調(diào)整監(jiān)控指標(biāo)對(duì)應(yīng)項(xiàng)。
JVM 參數(shù)回顧
結(jié)合性能優(yōu)化 - 高級(jí)進(jìn)階:JVM 常見優(yōu)化參數(shù),可啟動(dòng)時(shí)傳入:
-XX:+UseG1GC -Xms2048m -Xmx2048m -XX:+AlwaysPreTouch -XX:MaxMetaspaceSize=256m -XX:ReservedCodeCacheSize=240m -XX:MaxDirectMemorySize=512m
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps -XX:ErrorFile=/path/to/hs_err_pid%p.log
-Xlog:gc*,gc+age=trace,safepoint:file=logs/gc.log:utctime,pid,tags:filecount=5,filesize=100m根據(jù)硬件和應(yīng)用特點(diǎn)調(diào)整堆大??;若GC停頓問(wèn)題突出,可結(jié)合 async-profiler 和 GC 日志深入分析。
應(yīng)用性能監(jiān)控與分布式追蹤
SkyWalking 集成
圖片
1.下載與部署
- 下載
SkyWalking Agent和后端服務(wù)(按存儲(chǔ)類型,如 Elasticsearch 存儲(chǔ)版)。 - 部署
SkyWalking后端:配置 Storage、UI、Collector。
2.啟動(dòng)應(yīng)用時(shí)添加 Agent
java -javaagent:/opt/skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=your-service-name \
-Dskywalking.collector.backend_service=collector-host:11800 \
-jar your-app.jar3.查看調(diào)用鏈與指標(biāo)
- 訪問(wèn) SkyWalking UI,可看到每次請(qǐng)求的調(diào)用鏈圖、各段耗時(shí)、數(shù)據(jù)庫(kù)/HTTP 調(diào)用詳情、JVM 指標(biāo)、GC 指標(biāo)。
- 結(jié)合 Prometheus 等指標(biāo),綜合判斷:若某接口響應(yīng)慢,可查看是哪一段(查詢、序列化、遠(yuǎn)程調(diào)用等)成為瓶頸。
4.報(bào)警與自動(dòng)化
- 可結(jié)合 SkyWalking 的告警和 Prometheus AlertManager 設(shè)置閾值告警。
- 定期分析熱點(diǎn)接口和突發(fā)異常請(qǐng)求流,制定優(yōu)化計(jì)劃。
各層優(yōu)化思路
Controller 層
- DTO 精簡(jiǎn)與分頁(yè): 避免一次性返回過(guò)大結(jié)果集;對(duì)列表數(shù)據(jù)使用分頁(yè)或流式方式(如
Spring MVC StreamingResponseBody)。 - JSON 序列化優(yōu)化: 選擇高性能序列化庫(kù)(Jackson 已較快,可開啟 Afterburner 模塊),避免將不必要字段序列化。
- 輸入校驗(yàn)與限流: 對(duì)異?;驉阂庹?qǐng)求提前攔截,減少無(wú)效處理。
- 冪等性與緩存: 對(duì)可緩存接口,如 GET 查詢,結(jié)合 HTTP 緩存頭或后端緩存減少重復(fù)計(jì)算。
Service 層
- 無(wú)狀態(tài)設(shè)計(jì):
Service Bean默認(rèn)單例無(wú)狀態(tài),避免在 Bean 中維護(hù)請(qǐng)求級(jí)狀態(tài)。 - 合理拆分與職責(zé)分離: 將復(fù)雜邏輯拆成小模塊,便于監(jiān)控與優(yōu)化。
- 異步與并行: 對(duì)于可并行處理的子任務(wù),可使用
CompletableFuture、異步消息隊(duì)列等;但要注意線程池配置與上下文傳遞。 - 緩存策略:
本地緩存(Caffeine): 低延遲、減輕遠(yuǎn)程調(diào)用壓力;監(jiān)控命中率,避免緩存污染。
分布式緩存(Redis): 適用于共享場(chǎng)景;注意 TTL 策略、防止緩存穿透(布隆過(guò)濾、請(qǐng)求預(yù)熱)、防止雪崩(加隨機(jī)過(guò)期)、防止擊穿(互斥鎖或預(yù)加載)。
- 避免重復(fù)計(jì)算與請(qǐng)求合并: 對(duì)重復(fù)請(qǐng)求可合并或去重,減少下游壓力。
- 分布式事務(wù)討論:
兩階段提交、TCC、本地消息表、MQ事務(wù)消息等方案都會(huì)增加延遲與資源占用;僅在必要場(chǎng)景使用。
圖片
優(yōu)先考慮補(bǔ)償事務(wù)與柔性事務(wù),實(shí)現(xiàn)最終一致性;通過(guò)冪等設(shè)計(jì)與補(bǔ)償邏輯將風(fēng)險(xiǎn)和性能開銷控制在可接受范圍內(nèi)。
圖片
如上圖,分布式事務(wù)要在改造成本、性能、時(shí)效等方面進(jìn)行綜合考慮。有一個(gè)介于分布式事務(wù)和非事務(wù)之間的名詞,叫作柔性事務(wù)。柔性事務(wù)的理念是將業(yè)務(wù)邏輯和互斥操作,從資源層上移至業(yè)務(wù)層面。
傳統(tǒng)事務(wù) vs 柔性事務(wù)
關(guān)于傳統(tǒng)事務(wù)和柔性事務(wù),我們來(lái)簡(jiǎn)單比較一下。
ACID
關(guān)系數(shù)據(jù)庫(kù),最大的特點(diǎn)就是事務(wù)處理,即滿足 ACID。
- 原子性(Atomicity): 事務(wù)中的操作要么都做,要么都不做。
- 一致性(Consistency): 系統(tǒng)必須始終處在強(qiáng)一致狀態(tài)下。
- 隔離性(Isolation): 一個(gè)事務(wù)的執(zhí)行不能被其他事務(wù)所干擾。
- 持久性(Durability): 一個(gè)已提交的事務(wù)對(duì)數(shù)據(jù)庫(kù)中數(shù)據(jù)的改變是永久性的。
BASE
BASE 方法通過(guò)犧牲一致性和孤立性來(lái)提高可用性和系統(tǒng)性能。
BASE 為 Basically Available、Soft-state、Eventually consistent 三者的縮寫,其中 BASE 分別代表:
- 基本可用(Basically Available): 系統(tǒng)能夠基本運(yùn)行、一直提供服務(wù)。
- 軟狀態(tài)(Soft-state): 系統(tǒng)不要求一直保持強(qiáng)一致狀態(tài)。
- 最終一致性(Eventual consistency): 系統(tǒng)需要在某一時(shí)刻后達(dá)到一致性要求。
互聯(lián)網(wǎng)業(yè)務(wù),推薦使用補(bǔ)償事務(wù),完成最終一致性。比如,通過(guò)一系列的定時(shí)任務(wù),完成對(duì)數(shù)據(jù)的修復(fù)。
DAO 層
ORM 使用注意:
- 懶加載原則: 避免無(wú)意觸發(fā)大量關(guān)聯(lián)查詢,合理使用
FetchType.LAZY,并在Service層通過(guò)顯式查詢或 DTO 投影避免 N+1。 - 批量操作: 對(duì)于大量寫場(chǎng)景,使用批量插入/更新。
SQL 優(yōu)化與索引: 分析慢查詢?nèi)罩?、使?nbsp;EXPLAIN 確認(rèn)索引命中,避免全表掃描。
分庫(kù)分表注意: 理解中間件實(shí)現(xiàn)原理,避免誤以為簡(jiǎn)單 SQL 實(shí)現(xiàn)即高效;關(guān)注路由開銷與合并成本。
數(shù)據(jù)庫(kù)連接池:
- HikariCP 默認(rèn)已非常高效,但仍需監(jiān)控活躍連接數(shù)、等待時(shí)長(zhǎng);根據(jù)業(yè)務(wù)并發(fā)調(diào)整最大連接數(shù),避免連接池耗盡或空閑過(guò)多浪費(fèi)資源。
- 在 Prometheus 中可通過(guò) HikariPool 指標(biāo)收集連接使用情況,適時(shí)調(diào)整。
緩存優(yōu)化
Caffeine: 適合本地緩存,低延遲;需監(jiān)控緩存大小、命中率、加載延遲;避免過(guò)大導(dǎo)致內(nèi)存占用過(guò)高。
Redis:
- 連接池配置: 監(jiān)控和調(diào)整 Lettuce/Redisson 連接數(shù);注意阻塞或過(guò)度并發(fā)導(dǎo)致連接耗盡。
- 數(shù)據(jù)序列化: 選擇高效序列化方式(如 JSON、Kryo、FST 等),兼顧可讀性與性能。
- 緩存策略: 參見上文防護(hù)策略;結(jié)合業(yè)務(wù)場(chǎng)景設(shè)計(jì)合理 TTL。
二級(jí)緩存: 對(duì)數(shù)據(jù)庫(kù)讀密集應(yīng)用,可考慮本地+分布式二級(jí)緩存架構(gòu);注意緩存一致性。
資源與線程管理
線程池配置:
- 對(duì)于異步任務(wù)、自定義 Executor,設(shè)置合適的
core/max pool size、queue size;監(jiān)控線程活躍度、隊(duì)列長(zhǎng)度,防止任務(wù)堆積。 - 對(duì)于定時(shí)任務(wù),避免過(guò)多定時(shí)線程爭(zhēng)搶資源。
非阻塞與異步:
- 若業(yè)務(wù)適合,可使用 WebFlux 或 Reactor,但需慎重考慮團(tuán)隊(duì)熟悉度與實(shí)際場(chǎng)景;異步場(chǎng)景要注意線程切換開銷和上下文傳遞。
- 對(duì)外 HTTP 調(diào)用可使用異步 HTTP 客戶端(如 WebClient),避免阻塞線程。
端到端測(cè)試與壓測(cè)
- 壓測(cè)工具: wrk、JMeter、Locust 等
- 測(cè)前準(zhǔn)備: 確保監(jiān)控、日志、profiling 準(zhǔn)備完畢;在測(cè)試環(huán)境部署與生產(chǎn)相近的架構(gòu)。
- 測(cè)試腳本設(shè)計(jì): 模擬真實(shí)業(yè)務(wù)流量,包括登錄、查詢、寫入等混合場(chǎng)景。
- 結(jié)果分析: 結(jié)合 Prometheus/Grafana 監(jiān)控?cái)?shù)據(jù)和火焰圖,找出瓶頸;反復(fù)調(diào)優(yōu)并回歸測(cè)試,評(píng)估改動(dòng)效果。
- 負(fù)載模型: 考慮漸增負(fù)載測(cè)試、穩(wěn)定性測(cè)試、持久壓力測(cè)試,觀察資源消耗與響應(yīng)曲線。
小結(jié)
- 指標(biāo)采集—剖析—優(yōu)化—驗(yàn)證是閉環(huán)流程: 始終保持對(duì)系統(tǒng)可觀測(cè)性。
- 漸進(jìn)式改動(dòng): 在非生產(chǎn)環(huán)境驗(yàn)證,避免一次性大改帶來(lái)風(fēng)險(xiǎn);生產(chǎn)環(huán)境小步部署與監(jiān)控回滾準(zhǔn)備。
- CI/CD 集成: 可在持續(xù)集成/部署流程中集成簡(jiǎn)單的健康檢查和性能基準(zhǔn)測(cè)試。
- 定期回顧: 定時(shí)檢查關(guān)鍵接口的性能指標(biāo),防止代碼或依賴升級(jí)帶來(lái)性能回退。
- 團(tuán)隊(duì)協(xié)作: 文檔化優(yōu)化經(jīng)驗(yàn),分享給團(tuán)隊(duì)成員,形成共識(shí)和規(guī)范。































