侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计高并发场景下的Spring MVC接口,支持10万QPS并保证数据一致性

2025-12-13 / 0 评论 / 4 阅读

题目

设计高并发场景下的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集群代理层实时统计