JAVA面试宝典 -《高并发设计:秒杀系统全流程方案》
·
文章目录
🔥《高并发设计:秒杀系统全流程方案》
1️⃣ 秒杀系统的挑战:从单点压力到系统雪崩
场景: 一场 0 元秒杀活动刚上线,1 秒钟涌入 10 万用户请求,仅 100 台服务器瞬间被击垮。
🔥 秒杀系统的三大挑战:
- 并发洪峰: QPS 突破极限,容易造成网关、数据库雪崩;
- 库存一致: 多人并发抢购,容易导致超卖、重复下单;
- 系统稳定性: 单一热点商品可能压垮整条链路。
类比:就像抢春运火车票,每一秒都是“生死时速”。
2️⃣ 流量削峰利器:令牌桶 vs 漏桶
🚰 漏桶算法(Leaky Bucket)
- 原理: 请求先进入“漏桶”,以固定速率出水处理。
- 特点: 限速均匀,不能处理突发高峰。
🪙 令牌桶算法(Token Bucket)
- 原理: 系统以固定速率生成“令牌”,请求必须持有令牌才能通过。
- 特点: 支持突发流量,控制整体速率。
🧪 Java 示例:Google RateLimiter 实现令牌桶
RateLimiter rateLimiter = RateLimiter.create(100); // 每秒 100 个请求
if (rateLimiter.tryAcquire()) {
// 执行秒杀逻辑
} else {
// 拒绝请求
}
✅ 小结:
| 对比点 | 漏桶 | 令牌桶 |
|---|---|---|
| 限速方式 | 固定出水速率 | 令牌速率 + 突发处理 |
| 抗突发能力 | 弱 | 强 |
| 秒杀推荐 | ❌ | ✅ |
3️⃣ 秒杀核心:库存扣减的 Redis + Lua 原子方案
🚀 为什么用 Redis?
- 快(内存级别);
- 支持并发访问;
- 支持原子操作(Lua 脚本);
💡 Lua 脚本方案:
-- check_stock.lua
local stock = tonumber(redis.call('get', KEYS[1]))
if stock <= 0 then
return -1
end
redis.call('decr', KEYS[1])
return 1
Java 调用:
String script = loadScript("check_stock.lua");
Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
Collections.singletonList("seckill:sku:12345"));
🛡 如何防止超卖 & 重复下单?
- 设置用户参与标志位 SETNX user:sku:{uid};
- Redis + Lua 一并执行标志设置与扣减库存;
- 库存为 0 时,立即 reject。
✅ 小结:
Redis + Lua 是高并发场景下的库存锁原子操作利器。
4️⃣ 热点商品隔离:避免单商品拖垮系统
❗问题:
某个爆款秒杀商品被百万用户盯上,缓存击穿 → 数据库扛不住。
🧯解决方案:
| 策略 | 说明 |
|---|---|
| 缓存预热 | 活动前将商品库存、详情预加载到 Redis 中 |
| 缓存分片 | 将热门商品 ID 拆分成多个逻辑片段分流压力 |
| 本地缓存 + 限流 | 高频访问前放一层 Caffeine、Guava 本地缓存 |
| 布隆过滤器 | 防止非法商品 ID 请求击穿缓存 |
✅ 小结:
热点隔离关键是:提前预热 + 层层缓存 + 限流限并发
5️⃣ 异步下单机制与事务补偿
🚧 同步下单的问题:
- Redis 扣库存 → 写订单 → 扣减余额 … 全流程太慢!
- 数据库压力山大,延迟高,失败率增加。
✅ 异步下单设计(削峰填谷)
客户端 → Redis 判断库存 → 放入 MQ 消息队列 → 订单服务异步消费下单
Java MQ 生产:
OrderMessage msg = new OrderMessage(userId, skuId);
rocketMQTemplate.convertAndSend("seckill-order-topic", msg);
订单服务消费:
@RocketMQMessageListener(...)
public class OrderConsumer implements RocketMQListener<OrderMessage> {
public void onMessage(OrderMessage msg) {
try {
orderService.create(msg);
} catch (Exception e) {
sendToCompensationTopic(msg); // 异常补偿机制
}
}
}
⚠ 补偿机制怎么做?
- 消费失败消息入“补偿队列”;
- 后台定时任务重试;
- 超时未支付订单 → 自动回滚库存。
6️⃣ 分布式限流实战
🌐 接入层限流
- Nginx:limit_req_zone 配置;
- Spring Gateway:
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
☁️ 应用层限流:Sentinel + Redis 滑动窗口
@SentinelResource(value = "seckillResource", blockHandler = "handleBlock")
public String doSeckill(...) {
// 秒杀逻辑
}
Redis 滑动窗口限流(简化)
List<Long> timestamps = redis.lrange("user:uid", 0, -1);
if (timestamps.countRecent(5s) > 10) {
return "请求过于频繁";
}
7️⃣ 秒杀系统完整架构图
+-----------+
| 网关 |
+-----------+
|
限流 + 黑名单
|
+------------+-------------+
| |
热点商品预热 普通商品
| |
Redis 缓存 Redis 缓存
| |
↓(扣库存+限流) ↓
+-----------+ +-------------+
| MQ 异步投递 |--------->| 订单微服务 |
+-----------+ +-------------+
|
数据库写入 + 补偿机制
8️⃣ 常见问题与应对策略
| 问题 | 应对方案 |
|---|---|
| 库存不一致 | Redis 原子扣减 + DB 最终校验 |
| 超卖/重复下单 | 用户限购标志位 + 幂等性校验 |
| MQ 消息丢失 | 消息可靠投递 + 补偿机制 |
| 配置更新不生效 | 配合 Nacos 配置中心热更新 |
| 分布式锁失效 | Redisson + WatchDog 自动续期 |
✅ 总结:构建稳定高可用的秒杀系统关键点
- ✅ 前端限流 + 接入层保护,挡住大部分无效流量;
- ✅ Redis + Lua 原子扣库存,确保库存准确;
- ✅ 异步下单 + MQ 解耦,大幅降低主链路压力;
- ✅ 热点隔离 + 多级缓存,防止单点拖垮全局;
- ✅ 限流 + 熔断 + 补偿机制,让系统更具“韧性”。
📌 秒杀系统是系统稳定性设计的“炼金石”,掌握这套设计体系,你将具备应对千万级并发场景的能力。
📚 推荐阅读:
如果你觉得文章对你有帮助,欢迎 点赞 + 收藏 + 转发,更多微服务实战干货持续更新中 💪!
更多推荐


所有评论(0)