题目
设计高并发场景下的Spring MVC接口,支持10万QPS并保证数据一致性
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
Spring MVC异步处理,分布式事务控制,缓存与数据库优化,限流熔断机制,消息队列削峰
快速回答
实现高并发Spring MVC接口需综合运用以下技术:
- 异步处理:使用DeferredResult或WebFlux释放Tomcat线程
- 缓存优化:Redis集群缓存热点数据,布隆过滤器防穿透
- 数据库分片:ShardingSphere分库分表+读写分离
- 事务控制:TCC/Saga分布式事务保证最终一致性
- 限流削峰:Sentinel限流 + Kafka异步处理
- 连接池优化:HikariCP配置合理连接参数
1. 架构设计原则
核心目标:通过分层架构分散压力:
- 客户端层:CDN静态资源缓存
- Web层:无状态设计支持水平扩展
- 服务层:线程池隔离关键服务
- 数据层:读写分离+分库分表
2. Spring MVC异步处理
原理:释放Tomcat线程处理IO等待,避免线程阻塞
@RestController
public class AsyncController {
@GetMapping("/high-concurrency")
public DeferredResult<ResponseEntity<String>> handleRequest() {
DeferredResult<ResponseEntity<String>> deferredResult = new DeferredResult<>();
CompletableFuture.supplyAsync(() -> {
// 1. 缓存查询
String data = redisTemplate.opsForValue().get("hot_key");
if(data == null) {
// 2. 数据库查询(带分布式锁)
data = fetchFromDBWithLock("hot_key");
}
return data;
}, taskExecutor).whenComplete((result, ex) -> {
if(ex != null) {
deferredResult.setErrorResult(ex);
} else {
deferredResult.setResult(ResponseEntity.ok(result));
}
});
return deferredResult;
}
}3. 缓存与数据库优化
多级缓存策略:
- L1:本地缓存(Caffeine,过期时间1s)
- L2:Redis集群(Codis/Twemproxy分片)
- 防穿透方案:
// 布隆过滤器初始化 BloomFilter<String> bloomFilter = BloomFilter.create( Funnels.stringFunnel(), 1000000, 0.01); // 请求处理 if(!bloomFilter.mightContain(key)) { return "Invalid Request"; // 拦截非法Key }
数据库优化:
- 分库分表:ShardingSphere按用户ID分片
- 连接池配置:
# HikariCP配置(10万QPS建议) spring.datasource.hikari.maximum-pool-size=200 spring.datasource.hikari.minimum-idle=50 spring.datasource.hikari.connection-timeout=3000
4. 分布式事务控制
TCC模式实现(以订单扣库存为例):
// Try阶段(资源预留)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean inventoryTry(Long productId, int count) {
// 检查库存并冻结
int affected = jdbcTemplate.update(
"UPDATE inventory SET frozen = frozen + ? WHERE product_id = ? AND available >= ?",
count, productId, count
);
return affected > 0;
}
// Confirm阶段
public void inventoryConfirm(Long productId, int count) {
jdbcTemplate.update(
"UPDATE inventory SET available = available - ?, frozen = frozen - ? WHERE product_id = ?",
count, count, productId
);
}
// Cancel阶段(补偿)
public void inventoryCancel(Long productId, int count) {
jdbcTemplate.update(
"UPDATE inventory SET frozen = frozen - ? WHERE product_id = ?",
count, productId
);
}5. 限流与熔断
Sentinel配置:
// 资源定义
@SentinelResource(
value = "highConcurrencyApi",
blockHandler = "handleBlock",
fallback = "handleFallback"
)
public ResponseEntity<String> businessLogic() { /*...*/ }
// 限流处理
public ResponseEntity<String> handleBlock(BlockException ex) {
return ResponseEntity.status(429).body("请求过快");
}
// 熔断降级
public ResponseEntity<String> handleFallback(Throwable t) {
return ResponseEntity.status(503).body("服务暂不可用");
}控制台规则配置:
- QPS阈值:单机5000(根据节点数动态调整)
- 熔断策略:慢调用比例(RT>100ms且比例>50%)
6. 消息队列削峰
Kafka异步处理架构:
@PostMapping("/create-order")
public ResponseEntity<String> createOrder(@RequestBody Order order) {
// 1. 基础校验
// 2. 发送Kafka(零拷贝提升性能)
kafkaTemplate.send("order_topic",
order.getUserId() % 10, // 按用户ID分区
order
);
return ResponseEntity.accepted().body("请求已接受");
}
// 消费者端
@KafkaListener(topics = "order_topic", concurrency = "16")
public void processOrder(Order order) {
// 异步处理核心业务
orderService.process(order);
}常见错误
- 线程池阻塞:同步调用Redis/DB导致线程耗尽
- 缓存雪崩:大量Key同时过期 → 设置随机TTL
- 事务超时:分布式事务未设置超时 → Seata全局超时配置
- 限流失效:网关层未统一限流 → Nginx+Lua脚本限流
最佳实践
- 压测指标:使用JMeter持续压测,关注99线延迟
- 弹性扩缩:Kubernetes HPA基于QPS自动扩缩Pod
- 监控体系:
- Prometheus监控线程池活跃度
- Grafana展示Redis命中率/DB连接池等待
- ELK收集慢查询日志
扩展知识
- WebFlux替代方案:响应式编程提升吞吐量30%+
- 数据分片策略:一致性Hash vs 范围分片
- 分布式ID生成:Snowflake vs Leaf-Segment
- 热点Key探测:Redis集群代理层实时统计