使用Spring提高接口吞吐量的常見(jiàn)方法
一、引言
在我早期參與的一個(gè)電商項(xiàng)目中,曾遭遇過(guò)一次“秒殺”場(chǎng)景的接口雪崩:用戶(hù)量激增,接口響應(yīng)緩慢,系統(tǒng)幾近崩潰。那次經(jīng)歷讓我深刻意識(shí)到: “接口吞吐量”是高并發(fā)系統(tǒng)的生命線。
吞吐量(Throughput)是衡量系統(tǒng)性能的關(guān)鍵指標(biāo),通常指單位時(shí)間內(nèi)系統(tǒng)可以處理的請(qǐng)求數(shù)量。面對(duì)高并發(fā),我們?cè)撊绾卫?Spring 構(gòu)建一個(gè)高吞吐、高可用的接口系統(tǒng)?
本文將結(jié)合我這些年的實(shí)戰(zhàn)經(jīng)驗(yàn),從經(jīng)典場(chǎng)景到核心代碼實(shí)現(xiàn),系統(tǒng)地分享在 Spring 中提升接口吞吐量的幾種常見(jiàn)手段。
二、哪些場(chǎng)景需要關(guān)注接口吞吐量?
- 大促秒殺:電商活動(dòng)接口瞬時(shí)訪問(wèn)量暴漲
- 實(shí)時(shí)數(shù)據(jù)上報(bào):IoT設(shè)備每秒數(shù)萬(wàn)請(qǐng)求
- 內(nèi)部高頻接口:服務(wù)間調(diào)用頻繁
- 熱點(diǎn)接口:首頁(yè)推薦、商品詳情等訪問(wèn)量大
三、Spring 提高接口吞吐量的幾種手段
1. 接口異步化處理 —— 解耦請(qǐng)求與處理邏輯
應(yīng)用場(chǎng)景:非實(shí)時(shí)返回的業(yè)務(wù),如短信發(fā)送、日志收集、消息推送。
實(shí)戰(zhàn)代碼:
@RestController
public class NotifyController {
@Autowired
private Executor asyncExecutor;
@PostMapping("/send-notify")
public ResponseEntity<?> sendNotify(@RequestBody NotifyRequest request) {
asyncExecutor.execute(() -> notifyService.send(request));
return ResponseEntity.ok("已接收");
}
@Bean
public Executor asyncExecutor() {
return Executors.newFixedThreadPool(10);
}
}
使用異步線程池,主線程快速返回,提高系統(tǒng)響應(yīng)速度和吞吐能力。
2. 請(qǐng)求緩存 —— 減少數(shù)據(jù)庫(kù)/遠(yuǎn)程調(diào)用壓力
應(yīng)用場(chǎng)景:商品詳情、配置數(shù)據(jù)、熱點(diǎn)用戶(hù)信息等讀多寫(xiě)少的數(shù)據(jù)。
實(shí)戰(zhàn)代碼(基于 Spring Cache + Redis):
@Cacheable(value = "product", key = "#productId")
public Product getProductById(Long productId) {
return productRepository.findById(productId).orElse(null);
}
結(jié)合 Redis 做讀緩存,可以顯著減輕數(shù)據(jù)庫(kù)壓力,提升 QPS。
3. 接口限流 —— 保護(hù)系統(tǒng)穩(wěn)態(tài)運(yùn)行
應(yīng)用場(chǎng)景:秒殺接口、登錄接口、支付接口等敏感資源。
實(shí)戰(zhàn)代碼(基于 Spring + Bucket4j):
@Aspect
@Component
public class RateLimitAspect {
private final Map<String, Bucket> cache = new ConcurrentHashMap<>();
@Around("@annotation(RateLimit)")
public Object limit(ProceedingJoinPoint pjp) throws Throwable {
String key = pjp.getSignature().toShortString();
Bucket bucket = cache.computeIfAbsent(key, k -> Bucket4j.builder()
.addLimit(Bandwidth.simple(100, Duration.ofSeconds(1)))
.build());
if (bucket.tryConsume(1)) {
return pjp.proceed();
} else {
throw new RateLimitExceededException();
}
}
}
動(dòng)態(tài)限流,防止服務(wù)因突發(fā)流量而雪崩。
4. 請(qǐng)求合并 —— 減少重復(fù)查詢(xún)
應(yīng)用場(chǎng)景:批量請(qǐng)求同一資源,如查詢(xún)多個(gè)用戶(hù)信息。
實(shí)戰(zhàn)代碼(利用 Guava + Future 合并請(qǐng)求):
public class UserBatchService {
private final LoadingCache<Long, CompletableFuture<User>> userCache = CacheBuilder.newBuilder()
.refreshAfterWrite(10, TimeUnit.MILLISECONDS)
.build(CacheLoader.asyncReloading(this::batchLoad, Executors.newFixedThreadPool(5)));
private CompletableFuture<Map<Long, User>> batchLoad(Set<Long> userIds) {
return CompletableFuture.supplyAsync(() -> userRepository.findByIds(userIds));
}
public CompletableFuture<User> getUser(Long id) {
return userCache.get(id);
}
}
請(qǐng)求合并降低數(shù)據(jù)庫(kù)壓力,提高單位時(shí)間處理能力。
5. 使用響應(yīng)式編程(Reactive)提升吞吐量
應(yīng)用場(chǎng)景:高并發(fā)、IO密集型接口(如 WebFlux + MongoDB)
示例代碼:
@RestController
public class ReactiveProductController {
@Autowired
private ProductReactiveRepository repo;
@GetMapping("/product/{id}")
public Mono<Product> getProduct(@PathVariable String id) {
return repo.findById(id);
}
}
Reactive 編程模型通過(guò)非阻塞 IO 提升資源利用率,提升吞吐量。
6. 連接池優(yōu)化(DB、Redis、HTTP)
應(yīng)用場(chǎng)景:數(shù)據(jù)庫(kù)連接、遠(yuǎn)程調(diào)用、緩存訪問(wèn)等。
- 使用 HikariCP 替代默認(rèn) DBCP(Spring Boot 默認(rèn))
- 使用連接池客戶(hù)端(如 Lettuce、OkHttp)
- 合理設(shè)置連接池大?。?code>maxPoolSize ≈ CPU 核心數(shù) * 2 + IO線程數(shù)
四、多策略組合優(yōu)化的真實(shí)案例
在一個(gè)用戶(hù)畫(huà)像平臺(tái)中,我們有接口 /api/user/portrait/{id},訪問(wèn)頻率極高,初始 QPS 僅能支撐 200 左右。
通過(guò)以下優(yōu)化組合,最終提升至 QPS > 3000+ :
| 優(yōu)化項(xiàng) | 效果提升 |
|---|---|
| Redis 緩存熱點(diǎn)數(shù)據(jù) | +5倍 |
| 接口異步化回調(diào) | +2倍 |
| 請(qǐng)求合并 | +2倍 |
| 限流保護(hù) | 穩(wěn)定系統(tǒng) |
| 響應(yīng)式重構(gòu) | IO 利用率大幅提升 |
五、總結(jié):高吞吐的本質(zhì)是“減負(fù) + 異步 + 限速 + 快取”
在高并發(fā)場(chǎng)景下,提升吞吐量不是“堆機(jī)器”,而是“做減法”。
總結(jié)起來(lái),有8年經(jīng)驗(yàn)的我認(rèn)為:
- 異步化:能異步就不要阻塞
- 緩存化:能緩存就不要重復(fù)查
- 限流化:能攔截就不要撐爆
- 批量化:能合并就不要重復(fù)
- 輕量化:能響應(yīng)式就不要阻塞式
六、附:性能優(yōu)化的思考路徑圖
+------------------+
| 性能瓶頸分析 |
+------------------+
↓
+--------------------------+
| 是 CPU 吞吐 還是 IO 阻塞? |
+--------------------------+
↓
+------------------------------------+
| 線程池優(yōu)化 | 緩存 | 異步 | 限流 | 批處理 |
+------------------------------------+
到此這篇關(guān)于使用Spring提高接口吞吐量的常見(jiàn)方法的文章就介紹到這了,更多相關(guān)Spring提高接口吞吐量?jī)?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Jenkins集成sonarQube實(shí)現(xiàn)代碼質(zhì)量檢查過(guò)程圖解
這篇文章主要介紹了Jenkins集成sonarQube實(shí)現(xiàn)代碼質(zhì)量檢查過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
一篇文章帶你Java Spring開(kāi)發(fā)入門(mén)
這篇文章主要為大家詳細(xì)介紹了Java Spring開(kāi)發(fā)入門(mén)學(xué)習(xí)教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-09-09
Java 中利用泛型和反射機(jī)制抽象DAO的實(shí)例
這篇文章主要介紹了Java 中利用泛型和反射機(jī)制抽象DAO的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-07-07
Java實(shí)現(xiàn)藍(lán)橋杯G將軍的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)藍(lán)橋杯G將軍的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
K8S(Docker)如何優(yōu)雅的關(guān)閉SpringBoot微服務(wù)
這篇文章主要介紹了K8S(Docker)如何優(yōu)雅的關(guān)閉SpringBoot微服務(wù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-01-01
Java項(xiàng)目啟動(dòng)成功、失敗信息實(shí)時(shí)反饋提醒問(wèn)題(郵件或者短信)
這篇文章主要介紹了Java項(xiàng)目啟動(dòng)成功、失敗信息實(shí)時(shí)反饋提醒問(wèn)題(郵件或者短信),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Java實(shí)現(xiàn)將Markdown轉(zhuǎn)換為純文本
這篇文章主要為大家詳細(xì)介紹了兩種在 Java 中實(shí)現(xiàn) Markdown 轉(zhuǎn)純文本的主流方法,文中的示例代碼講解詳細(xì),大家可以根據(jù)需求選擇適合的方案2025-03-03
JAVA JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)詳解
這篇文章主要介紹了JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)劃分原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2021-09-09

