秒杀系统的幂等,只做一层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
相关推荐
xieliyu.11 分钟前
计算机网络|数据链路层详解:MAC 地址、交换机、ARP 协议、CRC 校验
java·网络·笔记·计算机网络·java-ee
SimonKing15 分钟前
手机投屏到电脑,不用装任何 App,这个开源工具免费搞定:QtScrcpy
java·后端·程序员
Dawson Zhu17 分钟前
Agent 评估方法:评估环境、验证器与统计显著性
人工智能·语言模型·架构·aigc·agi
严同学正在努力21 分钟前
Oracle数据技术运维大全(下篇)
运维·数据库·ai·oracle·架构
学长毕业设计24 分钟前
基于SpringBoot的奶茶店服务管理系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
蛋先生DX27 分钟前
明明都是源码到CPU,各语言中间原理咋不是一个套路?
java·javascript·go
IT_陈寒29 分钟前
Vue的computed属性差点让我加班到凌晨
前端·人工智能·后端
萧瑟余晖32 分钟前
Java深入解析篇十三之Java日志API(JUL)详解
java·开发语言
SelectDB技术团队42 分钟前
StarRocks 适合做日志分析吗?
大数据·数据结构·后端·python·doris·日志分析·starrock
随遇而安zx1 小时前
Spring Cloud Gateway 微服务网关 设计思想与深度解析
java·spring cloud·微服务·架构