Redis 明明没有报错,为什么库存还是超卖了?一次线上事故完整复盘

发布时间:2026/6/10 18:52:03

Redis 明明没有报错,为什么库存还是超卖了?一次线上事故完整复盘 很多开发者认为只要 Redis 扣库存成功并且 Redis 没有报错就不会发生超卖。真实情况并非如此。本文通过一次电商秒杀系统的线上事故复盘完整分析从事故发生、排查过程、错误推断、根因定位到最终修复的全过程并总结高并发库存系统的工程实践。![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e32ed1231bf444d5a4229d47d53d7c48.png#pic_center一、事故背景项目是一套电商秒杀系统。技术架构Spring BootRedisMySQLRabbitMQNginx业务流程用户下单 ↓ Redis扣库存 ↓ 发送MQ ↓ 创建订单 ↓ 更新数据库库存活动开始前配置商品运动耳机 库存1000 预计流量8万活动开始后十分钟。客服收到投诉已经下单成功 却显示库存不足随后运营发现订单数1037 库存1000系统出现超卖。二、第一轮排查怀疑Redis异常第一反应自然是 Redis。检查CPU内存网络慢查询日志主从状态全部正常。监控没有任何异常。Redis 甚至没有一条错误日志。检查扣库存代码LongremainredisTemplate.opsForValue().decrement(stock:1001);if(remain0){thrownewRuntimeException(库存不足);}代码没有明显问题。Redis DECR 是原子操作。理论上不会超卖。三、错误方向分析错误方向1Redis不原子很多开发者会认为高并发下是不是 Redis 自己出了问题实际上Redis 单线程执行命令。DECR 本身具有原子性。所以Redis原子 ≠ 整个业务原子这是很多人的误区。错误方向2主从延迟有人怀疑读到了从库旧数据。检查后发现库存操作全部走主库。没有读写分离。排除。四、真正的问题出现了继续追踪链路。发现订单系统引入了 MQ。架构如下用户下单Redis扣库存发送MQ订单服务数据库事故期间。RabbitMQ 出现积压。部分消息发送超时。这里埋下了隐患。五、根因分析出现以下情况场景ARedis扣减成功 ↓ MQ发送失败 ↓ 订单创建失败库存减少。订单没有。此时系统进入不一致状态。为了恢复。运维执行库存补偿。库存1问题看似解决。实际上部分消息后来恢复成功。于是库存补偿 订单再次创建最终导致超卖。六、为什么监控没有发现技术监控只关注RedisMySQLMQCPU内存但缺少业务监控。例如库存扣减成功数 订单创建成功数 库存回滚数这些指标没人看。于是技术正常。业务异常。七、如何复现问题测试代码decreaseStock();sendMessage();thrownewRuntimeException();结果Redis库存减少 订单失败 库存未恢复数据开始不一致。当补偿逻辑介入时。风险进一步扩大。八、解决方案对比方案一分布式锁RLocklockredissonClient.getLock(stock);lock.lock();try{//扣库存}finally{lock.unlock();}优点简单。缺点吞吐量下降。方案二Lua脚本localstockredis.call(get,KEYS[1])iftonumber(stock)0thenreturn-1endredis.call(decr,KEYS[1])return1优点高性能。缺点无法解决链路一致性。方案三库存预占流程预占库存 ↓ 创建订单 ↓ 支付成功 ↓ 正式扣减失败则释放。这是很多大型电商的方案。九、幂等设计消费端必须保证if(orderExists(orderNo)){return;}否则消息重复投递。订单重复创建。库存再次异常。十、库存流水设计建立流水表CREATETABLEstock_flow(idBIGINT,order_noVARCHAR(64),product_idBIGINT,change_numINT,create_timeDATETIME);任何库存变化必须记录。方便审计。方便追溯。方便补偿。十一、最终架构Redis预扣库存发送MQ订单创建支付成功正式扣减库存失败回滚释放库存上线后经历多次大促。未再出现超卖。十二、事故复盘总结这次事故最重要的结论很多开发者把Redis原子操作等同于系统不会超卖实际上Redis 只能保证命令原子。不能保证整个业务链路一致。真正需要关注的是幂等补偿流水MQ可靠性业务监控我的建议如果你的系统日订单 1000直接数据库事务即可。如果秒杀抢购高并发活动一定要提前设计库存预占幂等控制MQ重试库存流水业务监控否则迟早会踩坑。结语线上事故最可怕的不是报错。而是系统看起来一切正常。监控一切正常。用户却已经受到影响。Redis 很强。但 Redis 不是银弹。真正解决超卖问题的从来不是一个命令而是一套完整的工程体系。如果你长期使用 Cursor、Claude Code、ChatGPT Plus、Gemini Advanced、Grok、Kiro 等工具也可以顺手了解 gpt108.com。它主要解决相关 AI 工具的订阅需求。但对于后端开发者来说工程设计能力永远比工具更重要。

相关新闻