接口幂等性设计:让重复调用不再危险
一、为什么重复调用防不胜防
网络超时、用户连点、消息队列重试……在分布式系统里,“同一个请求被执行多次”不是异常,而是常态。前端点击提交后迟迟没有响应,用户忍不住又点了一次;网关层遇到超时自动重试;消息队列消费失败后重新投递。如果接口本身没有做幂等设计,一次重复调用就可能产生重复订单、重复扣款、重复发奖。这类故障隐蔽性强、影响直接,往往是线上资损事故的头号来源。
二、什么是幂等
幂等(Idempotence)是一个数学概念:f(f(x)) = f(x)。把它落到接口设计上就是:用同样的请求参数调用一次和调用 N 次,最终产生的业务效果应该一样。
需要注意,幂等约束的是“效果”,而不是“返回值”。比如查询接口天然幂等;按 ID 删除资源通常也幂等,删两次和删一次结果一致;而“账户余额减 100”这类操作天生不幂等,重复执行一次就多扣一笔钱。区分操作是否天然幂等,是设计的第一步。
三、实现幂等的四种常用手段
第一种是唯一约束。给业务单号加上唯一索引,重复写入时数据库直接拒绝,这是最简单、也最可靠的一道防线,几乎零成本。
第二种是 Token 机制。下单或提交前先向服务端申请一个一次性 Token,真正的业务请求必须携带这个 Token,服务端校验通过后立即将其作废。Token 只能消费一次,天然防重,适合前端表单重复提交的场景。
第三种是状态机。给核心单据设计明确的状态流转,比如订单只有处于“待支付”时才能被支付。支付回调重复到达时,订单早已流转到“已支付”,后续请求直接返回历史成功结果,不再执行业务动作。
第四种是分布式锁配合“先查后做”。在关键链路上用请求唯一键加锁,拿到锁之后先查询业务单据是否存在,存在则直接返回历史结果,不存在才真正执行业务逻辑。
四、容易被忽视的三个细节
第一,并发下的“先查后做”必须加锁。如果没有锁,两个请求可能同时查到“记录不存在”,然后双双写入,幂等就失效了。锁的粒度要尽量小,锁住唯一键即可,不要锁住整个业务流程。
第二,读侧也要考虑重试语义。客户端超时后发起重试时,服务端可能其实已经执行成功。这时需要用请求 ID 把重试与首次请求关联起来,返回首次执行的结果,而不是重新执行一遍。
第三,幂等键要有生命周期。去重记录不能无限增长,否则存储会被撑爆。过期时间要和业务对账周期对齐:比如对账窗口是 7 天,去重键至少保留 7 天以上,再叠加一点缓冲。
五、小结
幂等不是某个中间件自带的功能,而是一种设计习惯:凡是会改变系统状态的接口,动手之前先问一句——“如果它被调用两次,会发生什么?”把唯一约束、状态机、一次性 Token 这些手段用在支付、下单、发奖等关键链路上,系统才能在超时、重试、网络抖动成为常态的环境里依然稳得住。
- 点赞
- 收藏
- 关注作者
评论(0)