秒杀系统的幂等,只做一层Redis判重远远不够

面试经常被问到幂等设计,很多人的回答是:用Redis的SETNX做个判重就行了。

这个回答不能说错,但只对了三分之一。

秒杀专栏第15篇写完了,专门讲幂等设计。在实际的秒杀系统中,幂等做一层是扛不住的,我们的方案是三层防护,从外到内:Redis SETNX抢占、数据库唯一索引、业务状态机,三层各管各的范围,缺一层就有漏洞。

先说Redis层。消费端收到消息后,用SETNX原子操作抢占处理权,同一个traceId只有第一个到达的消息能通过,后续重复消息直接跳过。这一层能挡住99%以上的重复请求。但问题是Redis不是万无一失的,宕机恢复后可能丢数据(取决于AOF的fsync策略),SETNX的key可能消失。这时候如果没有第二层兜底,重复请求就穿透到业务逻辑了。

第二层是数据库的唯一索引。在订单表的traceId字段上建唯一索引,即使Redis层漏过了重复请求,数据库的DuplicateKeyException也会阻止重复插入。消费端捕获这个异常后,不当错误处理,而是查询已有订单返回给前端。

第三层是业务状态机。前两层解决的是「不重复创建」,第三层解决的是「重复操作不改变结果」。支付回调来了两次,UPDATE语句的WHERE条件里带了order_status = 0,第一次成功更新,第二次影响0行直接忽略。一条带条件的UPDATE语句就够了,数据库行锁保证原子性。

这篇文章还讲了一个容易被忽视的细节:PROCESSING状态的过期时间设计。设了60秒过期,消费线程崩溃后key会自动过期,允许RocketMQ下一次重试。不设过期时间的话,处理中途崩溃后这条消息就永远无法被重试了。另外还区分了「确定性失败」和「临时异常」的不同处理方式,库存不足用markFail直接标记失败,网络超时用release删除key允许重试。

做了这么多年开发,见过不少线上事故是幂等没做到位引起的。重复扣库存、重复建单、重复发放权益,每一种都是资损。很多人知道要做幂等,但只做了一层就觉得够了。三层各有各的弱点,组合在一起才没有死角。

这个秒杀专栏从需求分析、架构设计到每一行核心代码,覆盖了秒杀系统从0到1的完整链路。不是泛泛地讲概念,而是每个方案背后为什么这么选、不这么做会出什么问题,都讲清楚了。如果你正在做高并发系统、准备面试、或者想系统地学一套生产级的秒杀方案,这个专栏能帮你省掉大量踩坑的时间。订阅专栏,少走弯路。

最近在知乎出了秒杀专栏,感兴趣的可以订阅一下。至于知识星球的,可以搜:

  • 老码头的技术浮生录

它是一个能实际帮你解决难题的星球。有问题的,找知心的Sam哥,支持无限次语音一对一解决你遇到的难题。另外后续我新写的所有对外的付费专栏,在星球内都是免费的,且可以拿到所有源代码。

我的知乎账号:

  • SamDeepThinking
相关推荐
需要8265 分钟前
分布式事务:Seata AT/TCC/SAGA 的取舍与踩坑
java·spring boot·分布式·spring·spring cloud
晨小安18 分钟前
ThreadLocal及其内存泄漏问题深度解析
java·jvm·tomcat·哈希表
狂奔蜗牛(bradley)33 分钟前
拒绝SOEM黑盒!死磕EtherCAT主站:ARM+FPGA架构、DC同步与状态机修复等,50+篇实战开发文档全公开
arm开发·fpga开发·架构
m0_5873830038 分钟前
深圳24小时自助健身房解决方案实战:从系统架构到部署指南
java·人工智能·spring boot·spring·系统架构·需求分析
郑州光合科技余经理1 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
辛迪聊物业数字化1 小时前
智慧社区SaaS平台架构拆解:从物业收费到IoT联动的落地实现
物联网·架构
我叫黑大帅1 小时前
Go日志库工程选型与逃逸分析评测报告
后端·面试·go
无序的浪1 小时前
测试博客-基于微服务的在线判题系统
java·spring cloud·docker·微服务·测试·在线判题
xfan_me2 小时前
维修保养记录精准版 API 对接实战指南
java·大数据·python
Keven-zhou2 小时前
不用先学前端框架,Java后端也能独立交付项目?飞算JavaAI实测
java