接口的幂等性如何设计?

一 、 幂等性理解

幂等,指执行一次或多次都得到相同的结果。既多次重复执行同一个操作,最终的结果和执行一次相同。

比如说:多次调用一个接口或者方法,调用的结果和单次调用的结果一致;或者接收多次消息中间件消息,进行消息处理,和接收单次消息结果一直。

二、幂等出现情况

接口超时重试或多次调用

可能由于网络等原因导致调用失败,而对接口调用添加失败重试的机制导致出现脏数据。

消息重复消费

常用消息中间件,比如Kafka、RocketMQ、RabbitMQ,一般在生产端和消费端都有重试机制,也就是同一消息很可能会被重复消费。如果业务无法保证多次消费的结果是一样的话,就可能出现脏数据。

三、保证幂等性方式

基于悲观锁

对操作数据进行加锁,使用数据库锁、Redis分布式锁、Zookeeper分布式锁等都可以。基于性能考虑,我们可以使用Redis分布式锁实现。

1
2
3
4
5
6
7
8
RLock lock = redissonClient.getLock("updateResource:" + resourceId);
try {
lock.lock();
...
} finally {
// 释放分布式锁
lock.unlock();
}

基于乐观锁

每次去拿数据的时候都认为别人不会修改,所以先不上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。 乐观锁可以使用版本号机制来实现。

1
update set version = version +1 , additional_info = ${additionalInfo} where resource_id = xxx and version = ${version};

基于唯一索引

使用数据库的唯一索引来实现。比如,我们给订单表的订单号添加唯一索引,当我们创建订单时,前端先通过接口获取订单号,请求后端时带上订单号,如果存在插入相同订单号就会报错,以此来实现幂等。对于消息队列,一般MQ消息都有messageId,messageId是唯一的,我们可以创建一张消息记录表,将messageId作为主键,如果重复消费那么就会存在相同的messageId,那么插入就会报错。

四、个人使用和理解

(1)通过redis进行分布式读写锁加锁处理,可以有效进行加锁时间、粒度进行把握,还有就是对于系统的扩展性也是更好的选择,对微服务、分布式大数据量的扩展都是一种好的选择。乐观锁对于大系统不是特别好控制。

(2)数据库的insert唯一性加锁机制,对于重复消费的mq进行幂等性是一种很好的选择

综合控制:对于实际性能考虑,可以把唯一性的token作为redis的指定时间存储,然后加入mysql类型的数据库的唯一性,这个对于消息消费可以。

对于业务高并发开发,则需要redis的redlock的分布式读写锁机制来保证


接口的幂等性如何设计?
https://leellun.github.io/2023/05/02/后端/高并发/2023-05-02-接口的幂等性如何设计?/
作者
leellun
发布于
2023年5月2日
许可协议