在高并发下,如何使用 Spring 提高接口的吞吐量?
作者:Java 后端开发工程师 · 8年实战经验
时间:2025年6月
标签:Spring、性能优化、接口吞吐量、高并发、缓存、限流、异步化
一、引言
在我早期参与的一个电商项目中,曾遭遇过一次"秒杀"场景的接口雪崩:用户量激增,接口响应缓慢,系统几近崩溃。那次经历让我深刻意识到: "接口吞吐量"是高并发系统的生命线。
吞吐量(Throughput)是衡量系统性能的关键指标,通常指单位时间内系统可以处理的请求数量。面对高并发,我们该如何利用 Spring 构建一个高吞吐、高可用的接口系统?
本文将结合我这些年的实战经验,从经典场景到核心代码实现,系统地分享在 Spring 中提升接口吞吐量的几种常见手段。
二、哪些场景需要关注接口吞吐量?
- 大促秒杀:电商活动接口瞬时访问量暴涨
- 实时数据上报:IoT设备每秒数万请求
- 内部高频接口:服务间调用频繁
- 热点接口:首页推荐、商品详情等访问量大
三、Spring 提高接口吞吐量的几种手段
1. ✅ 接口异步化处理 ------ 解耦请求与处理逻辑
应用场景:非实时返回的业务,如短信发送、日志收集、消息推送。
实战代码:
kotlin
@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);
}
}
使用异步线程池,主线程快速返回,提高系统响应速度和吞吐能力。
2. ✅ 请求缓存 ------ 减少数据库/远程调用压力
应用场景:商品详情、配置数据、热点用户信息等读多写少的数据。
实战代码(基于 Spring Cache + Redis):
kotlin
@Cacheable(value = "product", key = "#productId")
public Product getProductById(Long productId) {
return productRepository.findById(productId).orElse(null);
}
结合 Redis 做读缓存,可以显著减轻数据库压力,提升 QPS。
3. ✅ 接口限流 ------ 保护系统稳态运行
应用场景:秒杀接口、登录接口、支付接口等敏感资源。
实战代码(基于 Spring + Bucket4j):
java
@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();
}
}
}
动态限流,防止服务因突发流量而雪崩。
4. ✅ 请求合并 ------ 减少重复查询
应用场景:批量请求同一资源,如查询多个用户信息。
实战代码(利用 Guava + Future 合并请求):
kotlin
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);
}
}
请求合并降低数据库压力,提高单位时间处理能力。
5. ✅ 使用响应式编程(Reactive)提升吞吐量
应用场景:高并发、IO密集型接口(如 WebFlux + MongoDB)
示例代码:
less
@RestController
public class ReactiveProductController {
@Autowired
private ProductReactiveRepository repo;
@GetMapping("/product/{id}")
public Mono<Product> getProduct(@PathVariable String id) {
return repo.findById(id);
}
}
Reactive 编程模型通过非阻塞 IO 提升资源利用率,提升吞吐量。
6. ✅ 连接池优化(DB、Redis、HTTP)
应用场景:数据库连接、远程调用、缓存访问等。
- 使用 HikariCP 替代默认 DBCP(Spring Boot 默认)
- 使用连接池客户端(如 Lettuce、OkHttp)
- 合理设置连接池大小:
maxPoolSize ≈ CPU 核心数 * 2 + IO线程数
四、多策略组合优化的真实案例
在一个用户画像平台 中,我们有接口 /api/user/portrait/{id}
,访问频率极高,初始 QPS 仅能支撑 200 左右。
通过以下优化组合,最终提升至 QPS > 3000+ :
优化项 | 效果提升 |
---|---|
Redis 缓存热点数据 | +5倍 |
接口异步化回调 | +2倍 |
请求合并 | +2倍 |
限流保护 | 稳定系统 |
响应式重构 | IO 利用率大幅提升 |
五、总结:高吞吐的本质是"减负 + 异步 + 限速 + 快取"
在高并发场景下,提升吞吐量不是"堆机器",而是"做减法"。
总结起来,有8年经验的我认为:
- 异步化:能异步就不要阻塞
- 缓存化:能缓存就不要重复查
- 限流化:能拦截就不要撑爆
- 批量化:能合并就不要重复
- 轻量化:能响应式就不要阻塞式
六、附:性能优化的思考路径图
lua
+------------------+
| 性能瓶颈分析 |
+------------------+
↓
+--------------------------+
| 是 CPU 吞吐 还是 IO 阻塞? |
+--------------------------+
↓
+------------------------------------+
| 线程池优化 | 缓存 | 异步 | 限流 | 批处理 |
+------------------------------------+
🚀 你的接口吞吐优化做得怎么样?
欢迎在评论区分享你在接口高并发下的优化经验或踩过的坑,我们一起成长!