接口的幂等性如何设计?
一 、 幂等性理解
幂等,指执行一次或多次都得到相同的结果。既多次重复执行同一个操作,最终的结果和执行一次相同。
比如说:多次调用一个接口或者方法,调用的结果和单次调用的结果一致;或者接收多次消息中间件消息,进行消息处理,和接收单次消息结果一直。
二、幂等出现情况
接口超时重试或多次调用
可能由于网络等原因导致调用失败,而对接口调用添加失败重试的机制导致出现脏数据。
消息重复消费
常用消息中间件,比如Kafka、RocketMQ、RabbitMQ,一般在生产端和消费端都有重试机制,也就是同一消息很可能会被重复消费。如果业务无法保证多次消费的结果是一样的话,就可能出现脏数据。
三、保证幂等性方式
基于悲观锁
对操作数据进行加锁,使用数据库锁、Redis分布式锁、Zookeeper分布式锁等都可以。基于性能考虑,我们可以使用Redis分布式锁实现。
1 |
|
基于乐观锁
每次去拿数据的时候都认为别人不会修改,所以先不上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。 乐观锁可以使用版本号机制来实现。
1 |
|
基于唯一索引
使用数据库的唯一索引来实现。比如,我们给订单表的订单号添加唯一索引,当我们创建订单时,前端先通过接口获取订单号,请求后端时带上订单号,如果存在插入相同订单号就会报错,以此来实现幂等。对于消息队列,一般MQ消息都有messageId,messageId是唯一的,我们可以创建一张消息记录表,将messageId作为主键,如果重复消费那么就会存在相同的messageId,那么插入就会报错。
四、个人使用和理解
(1)通过redis进行分布式读写锁加锁处理,可以有效进行加锁时间、粒度进行把握,还有就是对于系统的扩展性也是更好的选择,对微服务、分布式大数据量的扩展都是一种好的选择。乐观锁对于大系统不是特别好控制。
(2)数据库的insert唯一性加锁机制,对于重复消费的mq进行幂等性是一种很好的选择
综合控制:对于实际性能考虑,可以把唯一性的token作为redis的指定时间存储,然后加入mysql类型的数据库的唯一性,这个对于消息消费可以。
对于业务高并发开发,则需要redis的redlock的分布式读写锁机制来保证