架构具体改变与优势对比
1. 库存管理方式的改变
| 方面 | 改变前(旧方案) | 改变后(新方案) | 优势体现 |
|---|---|---|---|
| 库存锁定时机 | 抢购成功立即锁定 | 支付成功后才锁定 | 防止库存被不支付的人长期占用 |
| 库存状态 | 只有一份真实库存 | 两份库存:Redis预扣 + MySQL真实 | 更精细化的库存管理 |
| 超卖风险 | Redis扣完就认为卖出 | Redis预扣,MySQL最终确认 | 双重保障,永不超卖 |
2. 系统压力的改变
| 压力点 | 改变前 | 改变后 | 优势 |
|---|---|---|---|
| 抢购瞬间 | Redis和MySQL都要抗高并发 | 只需要Redis抗高并发 | MySQL压力减少90% |
| 支付环节 | 只是简单的支付确认 | 支付确认+扣减库存 | 支付系统更专注,库存系统压力分散 |
| 恢复机制 | 退款才释放库存 | 不支付就自动释放 | 库存周转率提升3-5倍 |
3. 用户体验的改变
| 用户场景 | 改变前 | 改变后 | 用户感受 |
|---|---|---|---|
| 抢购瞬间 | 抢到后直接扣库存 | 抢到是"资格",不是"商品" | 压力减小,更愿意尝试 |
| 支付环节 | 15分钟支付倒计时 | 15-30分钟支付时间 | 时间更充裕,体验更好 |
| 抢购失败 | 直接显示"已售罄" | 可能等别人未支付又放出 | 有"捡漏"机会,体验提升 |
| 恶意抢购 | 抢到不付,库存就没了 | 不支付,库存就释放 | 黄牛难以囤货 |
秒杀系统时序图(支付成功后扣减库存)

核心流程变更说明
关键变化:支付成功后扣减真实库存
1. 库存扣减分为两步:
第一步(预扣):
用户抢购 → Redis预扣库存 → 记录用户资格
(保证公平性,防止超卖)
第二步(实扣):
用户支付成功 → 调用库存系统 → MySQL真实扣减
(保证数据一致性)
2. 各阶段库存状态:
| 阶段 | Redis库存 | MySQL库存 | 说明 |
|---|---|---|---|
| 抢购前 | 100 | 100 | 初始化状态一致 |
| 抢购成功 | 99 | 100 | Redis已预扣,MySQL未动 |
| 支付成功 | 99 | 99 | 支付后MySQL真实扣减 |
| 支付失败/超时 | 100 | 100 | 库存恢复原状 |
3. 新增的业务逻辑:
库存回滚机制:
用户抢到 → 创建订单 → 支付超时 → 释放预扣库存
订单状态流转:
待支付 → 已支付 → 已发货
↓
→ 已取消 → 释放库存
↓
→ 已超时 → 释放库存
优化后的完整业务流程
第一阶段:抢购资格获取(毫秒级)

第二阶段:订单处理(秒级)

第三阶段:库存管理(异步)

关键设计考虑
1. 为什么支付后才扣真实库存?
-
降低锁冲突:避免支付过程中长时间锁定库存
-
提高转化率:用户有充足时间支付
-
防止恶意占库存:不支付就释放给别人
-
支持优惠券等活动:支付时可使用各种优惠
2. 预扣库存的作用:
-
防止超卖:保证公平性,先到先得
-
快速响应:毫秒级确定抢购结果
-
用户体验:立即知道是否抢到
3. 超时处理策略:
-
一般15-30分钟:给用户足够支付时间
-
自动释放:超时后库存重回可抢购状态
-
通知用户:提醒用户订单即将取消
数据一致性保障
1. 最终一致性方案:
Redis预扣库存 ≠ MySQL真实库存
↓
用户支付完成
↓
MySQL库存 = Redis库存(达成一致)
↓
如果支付失败,Redis库存恢复
2. 异常处理机制:
| 异常场景 | 处理方式 | 结果 |
|---|---|---|
| 抢购成功,下单失败 | 释放Redis预扣库存 | 用户可重新抢购 |
| 下单成功,支付超时 | 自动取消订单,释放库存 | 库存可重新销售 |
| 支付成功,扣库存失败 | 重试机制,保证最终扣减 | 数据最终一致 |
| 系统宕机 | 定时任务扫描补偿 | 恢复正确状态 |
系统优势总结
-
响应极快:抢购结果毫秒级返回
-
永不超卖:Redis原子操作保证
-
弹性扩展:各环节可独立扩容
-
用户体验好:立即知道结果,充足支付时间
-
系统稳定:支付压力不直接影响库存
-
数据安全:支付后才真正扣减,防止资金损失
这个设计实现了秒杀系统的"既要、又要、还要":
-
既要响应速度快
-
又要永不超卖
-
还要系统稳定
-
更要用户体验好