什么是幂等?
任意多次执行所产生的影响均与一次执行的影响相同就可以称为幂等
什么是消息幂等?
当出现消费者对某条消息重复消费的情况时,重复消费的结果与消费一次的结果是相同的,并且多次消费并未对业务系统产生任何负面影响
为什么我们要保证幂等性,不保证幂等性,会不会有问题?
这个问题其实没法准确回答。回答这个问题的根源得从业务场景上进行分析。比如正常业务情况下,我们是不允许同个订单重复支付,这种业务场景我们就需要确保幂等性。再比如日志记录,这种业务场景,我们可能就不需要做幂等判断。
因此是否要保证幂等性,得基于业务进行考量
消息队列的消费幂等性如何保证?
没法保证。前面说了要保证幂等性,得基于业务场景进行考量。消息队列他本身就不是给你用来做业务幂等性用的。如果你要实现业务幂等性,靠消息队列是没法帮你完成的,你自己得根据自身业务场景,来实现幂等。
常用的业务幂等性保证方法
1、利用数据库的唯一约束实现幂等
比如将订单表中的订单编号设置为唯一索引,创建订单时,根据订单编号就可以保证幂等
2、去重表
这个方案本质也是根据数据库的唯一性约束来实现。其实现大体思路是:首先在去重表上建唯一索引,其次操作时把业务表和去重表放在同个本地事务中,如果出现重现重复消费,数据库会抛唯一约束异常,操作就会回滚
3、利用redis的原子性
每次操作都直接set到redis里面,然后将redis数据定时同步到数据库中
4、多版本(乐观锁)控制
此方案多用于更新的场景下。其实现的大体思路是:给业务数据增加一个版本号属性,每次更新数据前,比较当前数据的版本号是否和消息中的版本一致,如果不一致则拒绝更新数据,更新数据的同时将版本号+1
5、状态机机制
此方案多用于更新且业务场景存在多种状态流转的场景
6、token机制
生产者发送每条数据的时候,增加一个全局唯一的id,这个id通常是业务的唯一标识,比如订单编号。在消费端消费时,则验证该id是否被消费过,如果还没消费过,则进行业务处理。处理结束后,在把该id存入redis,同时设置状态为已消费。如果已经消费过了,则不进行处理。
演示
例子使用springboot2加kafka来演示一下使用token机制如何实现消费端幂等
1、application.yml
spring:
redis:
host: