秒杀系统的幂等,只做一层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
相关推荐
csdn2015_1 小时前
lambdaQuery 加 or
java·linux·服务器
Ribou1 小时前
Kubernetes v1.35.2 基于 Cilium Gateway API 的服务访问架构
架构·kubernetes·gateway
天涯海风1 小时前
写一个录音并保存到手机的工具 安卓工具类
android·java·智能手机
sjsjsbbsbsn1 小时前
RAG 基础学习总结
java·数据库·学习
米高梅狮子1 小时前
09.kube-proxy、Ingress和Network Policy
云原生·容器·架构·kubernetes·自动化
程序员老邢1 小时前
【产品底稿 08】商助慧 AI 仿写实战复盘:RAG 知识库 + 大模型联动,一键生成技术底稿
人工智能·spring boot·后端·ai·语言模型·milvus
剑飞的编程思维1 小时前
传统制造业数字化转型|架构评估核心全维度清单
架构
IT_陈寒2 小时前
JavaScript的闭包差点让我加班到凌晨
前端·人工智能·后端
今天又在写代码2 小时前
Docker部署
java·阿里云·docker