Spring Boot微服务接口幂等设计实战:Redis分布式锁与数据库唯一约束方案

微服务架构下的接口幂等设计,是保证数据一致性的基础问题。客户端重试、消息重复投递、异步回调重放,都会导致同一笔业务被执行多次。幂等的本质是让同一请求只生效一次,本文围绕Spring Boot微服务给出两种主流方案:Redis分布式锁幂等和数据库唯一约束幂等,覆盖实现细节和适用场景。

幂等设计的基本场景

幂等问题集中在三类入口:写接口(创建订单、转账、扣减库存)、消息消费端(MQ重复投递)和外部回调(支付成功通知)。判断是否幂等,先看业务动作天然是否可重复:查询天然幂等,纯新增不幂等,更新操作要看更新目标是否确定。对不幂等的写操作,都要做幂等保护。

方案一:Redis分布式锁与幂等令牌

实现思路是客户端携带唯一请求ID(幂等键),服务端用Redis的SETNX把请求ID写入,写成功后执行业务,执行完释放锁。重复请求到达时SETNX返回失败,直接返回之前的结果。Spring Boot中实现:

public boolean tryIdempotent(String key) {    String result = redisTemplate.opsForValue()        .setIfAbsent(key, "1", Duration.ofMinutes(5));    return Boolean.TRUE.equals(result);}
// 业务入口if (!tryIdempotent("order:" + requestId)) {    return alreadyHandled(requestId);}doCreateOrder(request);

setIfAbsent是原子操作,Redis单线程特性保证同一key只可能被一个请求抢占。锁的过期时间要大于业务最长时间,避免业务没执行完锁就过期,导致并发执行。key的过期时间可按业务场景设置,通常设置5分钟到30分钟。

方案二:数据库唯一约束

数据库唯一约束是更强的兜底方案。在业务表上建唯一索引(比如order_no、request_id),重复插入直接抛duplicate key异常,业务代码catch后返回已处理结果。

CREATE TABLE t_order (  id BIGINT AUTO_INCREMENT PRIMARY KEY,  order_no VARCHAR(64) NOT NULL,  UNIQUE KEY uk_order_no (order_no)) ENGINE=InnoDB;

这个方案不依赖外部组件,适合对一致性要求高的核心写操作。唯一索引会占一点磁盘,但带来的安全性值得。

消息消费幂等与回调幂等

MQ消费端收到重复消息很常见,生产端重试、消费端未提交消费位点都会导致重发。消费处理前先查本地幂等表:记录已消费的消息ID。消费成功写一条记录,重复消息直接跳过。配合Redis锁作为第一道防护,数据库唯一约束作为第二道,双保险。

支付回调同理,用回调订单号做幂等键,重复回调只更新一次状态,且状态更新用乐观锁version,避免并发更新覆盖。

方案选型与踩坑记录

选型结论:Redis分布式幂等适合高QPS、非强一致场景,性能和伸缩性好;数据库唯一约束适合核心资金、订单场景,强一致、无单点。实践中两者可以叠加:Redis做流量层拦截,DB唯一约束做最终一致性兜底。

常见坑有三个:Redis锁的过期时间设太短,业务没跑完锁被续期是解决;幂等键用错了维度(客户端每次生成新ID导致幂等失效);只做了接口层幂等,忽略了消息层幂等。解决思路:锁续期用看门狗模式、幂等键用服务端签名校验并绑定业务字段、消息消费全部走幂等表。三招落地后,重复请求带来的数据问题基本能堵住。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/springboot-wei-fu-wu-jie-kou-mi-deng-she-ji-shi-zhan-redis/

(0)
小编小编
上一篇 1天前
下一篇 1天前

相关推荐