Spring Boot微服务架构下的电商秒杀系统设计与实现
Spring Boot微服务架构下的电商秒杀系统设计与实现
1. 场景背景
在大型电商平台(如双11)中,秒杀活动是典型的高并发、低延迟、强一致性的业务场景。用户瞬时流量可达百万QPS,而商品库存仅数百件,极易引发超卖、数据库雪崩、服务宕机等问题。
本文以某一线大厂真实面试题为蓝本,结合Java技术栈(Spring Boot 3.x + JDK 17 + Jakarta EE),从面试提问 → 技术剖析 → 代码落地 → 架构演进全流程展开,适合中高级Java工程师深度学习。
2. 面试三轮递进式提问(附答案详解)
🔹 第一轮:基础建模与单体瓶颈
Q1:请用Spring Boot写一个最简秒杀接口,要求校验库存、扣减库存、生成订单。注意线程安全。
@RestController
public class SeckillController {
@Autowired private SeckillService seckillService;
@PostMapping("/seckill/{itemId}")
public ResponseEntity<String> doSeckill(@PathVariable Long itemId) {
try {
boolean success = seckillService.trySeckill(itemId);
return success ? ResponseEntity.ok("抢购成功") : ResponseEntity.badRequest().body("库存不足");
} catch (Exception e) {
return ResponseEntity.status(500).body("系统繁忙");
}
}
}
@Service
public class SeckillService {
@Autowired private ItemRepository itemRepo;
@Autowired private OrderRepository orderRepo;
// ❌ 错误示范:DB层面无并发控制 → 超卖!
public boolean trySeckill(Long itemId) {
Item item = itemRepo.findById(itemId).orElseThrow();
if (item.getStock() > 0) {
item.setStock(item.getStock() - 1);
itemRepo.save(item);
orderRepo.save(new Order(itemId));
return true;
}
return false;
}
}
✅ 正确解法(第一层防御):数据库乐观锁 + 原子更新
UPDATE item SET stock = stock - 1 WHERE id = ? AND stock > 0;
@Modifying
count = itemRepo.decreaseStock(itemId); // 返回影响行数
if (count == 0) throw new IllegalStateException("库存已抢光");
🔹 第二轮:性能优化与分布式挑战
Q2:当QPS达10万+,数据库扛不住怎么办?请设计缓存+消息队列异步化方案,并说明Redis如何防止缓存击穿?
✅ 架构升级:Redis预减库存 + Kafka异步落库
- 使用
Redis Lua脚本原子性执行:GET stock,DECR stock,LPUSH seckill_queue; - 若
DECR返回负数 → 拒绝请求(前端友好提示); - 成功后发Kafka消息
{"itemId":1001,"userId":123456}至seckill-order-topic; - 消费者组异步创建订单,失败则重试+死信队列告警。
🔒 防击穿方案:
- 热点Key永不过期 + 后台定时刷新;
- 或
SETNX key_lock 1 EX 30获取锁,未命中则回源DB并重建缓存; - 结合
Caffeine本地缓存(Guava Cache已弃用),降低Redis压力。
🔹 第三轮:终极一致性与可观测性
Q3:若Kafka消费失败导致订单丢失,或Redis与DB库存不一致,如何保障最终一致性?请给出监控埋点与补偿方案。
✅ 分布式事务三板斧:
- TCC模式(Try-Confirm-Cancel):
- Try:Redis预占库存(
SECKILL:ITEM:1001:PRE)、冻结用户账户余额; - Confirm:DB扣库存+生成订单+扣余额(全部成功才提交);
- Cancel:任一失败则释放预占资源;
- Try:Redis预占库存(
- Saga模式(推荐):
- 步骤1:发MQ → 创建订单(状态=PROCESSING);
- 步骤2:监听MQ → 扣减库存(失败则发逆向MQ:取消订单);
- 补偿任务:Quartz扫描超时PROCESSING订单,自动回滚;
- 监控闭环:
- Micrometer + Prometheus采集指标:
seckill_success_rate{env="prod"}; - ELK收集Kafka消费延迟日志;
- Grafana看板联动告警(如:
rate(kafka_consumergroup_lag{group=~"seckill.*"}[5m]) > 1000)。
- Micrometer + Prometheus采集指标:
3. 技术栈全景图(严格对齐JD要求)
| 类别 | 技术选型 | 说明 | |--------|-----------|------| | 核心平台 | JDK 17 + Spring Boot 3.2 | 支持虚拟线程(spring.threads.virtual.enabled=true)提升吞吐 | | Web框架 | Spring WebFlux | 替代Servlet容器,响应式编程处理长连接推送 | | 缓存 | Redis 7 + Lettuce + Redisson | 分布式锁、延时队列(RDelayedQueue) | | 消息 | Kafka 3.5 + Spring Kafka | Exactly-Once语义 + 事务性生产者 | | ORM | JPA 3.1 + Hibernate 6.2 | @DynamicUpdate 减少SQL冗余 | | 安全 | Spring Security 6 + JWT + OAuth2 Resource Server | 秒杀接口需SCOPE_SECKILL权限 | | 可观测 | Micrometer + Prometheus + Grafana + Jaeger | 全链路TraceId透传 | | CI/CD | GitHub Actions + Docker + K8s Helm | 多环境灰度发布(canary标签) |
4. 小白也能懂的总结
⚡️ 记住三句话:
- 流量要削峰 → 前端答题/验证码 → Nginx限流 → Redis预减 → Kafka缓冲;
- 数据要兜底 → DB主键唯一约束防重复下单 → 定时对账任务校验Redis/DB库存差;
- 故障要可见 → 所有关键步骤打
log.info("SECKILL_STEP_1", kv("itemId", itemId))→ Micrometer记录Timer.builder("seckill.latency").register(meterRegistry)。
📌 延伸思考(面试官最后话术):
“今天的问题覆盖了高并发系统的核心矛盾——一致性 vs 可用性 vs 分区容错性。你展现了扎实的工程能力,但分布式系统的复杂性远不止于此。比如:如何用Resilience4j实现熔断降级?WebSocket如何实时推送抢购结果?欢迎你回家后,用Quarkus重构这个服务,我们下次聊聊云原生下的极致性能优化。祝你拿到心仪的offer!”
© 2024 CSDN技术专栏|转载请注明出处
更多推荐


所有评论(0)