MQ消费重复
# MQ消费重复
# 幂等的概念介绍
幂等的含义是:对于相同的请求,调用多次业务与调用一次业务,其对业务相关资源的影响只会有一次,举个例子,支付的时候不管你点了几次支付,实际只会扣减一次余额。
防重和幂等是有区别的。
防重主要是为了避免产生重复数据,对于接口的返回没有太多要求。而幂等除了避免产生重复数据之外,还要求每次请求都返回一样的结果。 并且防重更加侧重于解决来自用户的恶意重复请求,从而消耗大量服务器资源,幂等更加侧重于整个服务之间由于种种问题而导致的重复调用。
# 解决MQ重复消费(幂等去重表)
解决MQ重复消费本质就是要对消息的消费状态做一个记录,以便之后该条消息的重复消费时候能够有依据去判断是否是重复消费,具体表现为存储+唯一key。在进行业务处理时,查询下是否已处理过这个唯一key的消息;如果存在就不进行后续业务处理;如果不存在就继续后续业务的处理
# 具体方案
# 基于数据库强校验(事务)
在消费消息的时候,首先会像去重表内插入一条记录,然后进行业务操作,去重表与业务的业务表要为同一个事务。当重复消费的时候,就会因为不能向去重表里插入记录而失败回滚。从而解决重复消费
mysql去重表方案中 如果消费失败,那么记录表和业务表会一起回滚,给消息的重试提供机会,消费成功,则会阻止重试。
该方法过于依赖事务,必然导致其处理速度不高,但是安全性好,实现也简单,基本不需要引入额外的组件。
该方案的优缺点
优点 | 缺点 |
---|---|
在并发情况下,只会严格执行一次。数据库唯一性+事务回滚能保证业务只执行一次; 不会存在幂等校验穿透的问题 | 处理速度较慢: 处理性能上和后续的redis方案比起来,慢一个数量级。毕竟有事务加持;另外插入唯一数据时极大可能读磁盘数据,进行唯一性校验 |
可提供查询流水功能:处理流水记录的持久化,在某些异常问题排查情况下,还能较为方便的提供查询记录 | 历史数据需要额外进行清理:如果采用mysql进行存储,历史记录数据的清理,需要自己单独考虑和处理, |
实现简单:实现难度还是较为简单的,一个注解能包裹住事务+回滚 | |
适用资金类业务:非常适合涉及资金类业务的防重;毕竟涉及到钱,不把数据持久化和留痕,心理总是不踏实 | |
架构上简约:架构上也简单,大多数业务系统都需要依赖数据库。 |
# 基于redis的弱校验(非事务)
向redis里新增幂等标识 使用lua脚本,因为逻辑是先查再插入要保证操作的原子性。
引入延迟队列保证一定能消费成功
redis lua+延时消息
优点 | 缺点 |
---|---|
处理速度快 | 因为数据有过期时间和redis自身特性;防重数据有丢失可能性,结果就是有不能防重的风险 |
无需自动清理唯一key记录 | 实现上比起数据库,稍显复杂,需要写lua脚本 |
消息一定能消费成功 | 架构上稍显复杂,为了保证一定能消费成功,引入了延时队列 |
该方案不依赖数据库的事务,处理速度快,性能高,但是实现架构复杂,且存在防重数据丢失从而失去防重效果的风险。
核心业务流程
# 建议
数据库强校验:适合涉及资金类业务的防重;毕竟涉及到钱。
Redis弱校验:适合对吞吐量,实时性要求高的业务。
上次更新: 2024/08/09, 16:07:34