Rabbitmq消息重复消费问题(幂等性保障)

消息百分百投递架构

在《消息可靠性保证》篇章中,我通过生产者确认机制 保障了消息会发送到MQ中,但是在生产者与MQ建立过程的时候出现了网络抖动,连接建立失败,生产者就感知不到MQ返回的ack/nack,无法完全保障消息投递到MQ中,因此这里介绍如何保障生产者百分百将消息投递到MQ。

  • step1:首先把消息信息(业务数据)存储到数据库中,紧接着,我们再把这个消息记录也给存储到一张消息记录表中,并且在消息记录表中指定一个状态字段status来记录消息的投递状态。将status设为0,表示还未被投递
  • step2:发送消息给MQ Broker节点(采用Confirm确认机制发送消息,会有异步的返回结果)
  • step3,4:生产者端接收MQ Broker节点返回的Confirm确认消息结果,然后进行更新消息记录表中的消息状态。将status设为1,表示投递成功
  • step5:但是在消息确认这个过程中可能出现网络抖动,MQ Broker端异常等原因导致 返回消息失败,这个时候需要生产者对消息进行可靠性投递,保障消息不丢失。所以我们需要一个定时任务(比如每1分钟拉取一些消息的状态信息,当然这个消息也可以设置一个超时时间,比如超过1分钟status=0,也就说明1分钟内,该消息没有被投递成功,那么就会被定时任务拉取出来)
  • step6:接下来我们把status=0的消息进行重新投递 retry send
  • step7:我们可以设置最大重试次数,比如投递3次还是失败,就可以把该消息的状态status标记为2,交给人工解决(或者把这些记录到一张失败表中)

通过以上步骤就能保障消息的百分百投递成功!!!

引出重复消费问题

step2 网络抖动没有投递成功,并不会照成重复消费问题,因为消息并没有投递到MQ中。而step3 此时MQ已经接收到该消息,返回ack时出现网络抖动,导致生产者接收不到MQ返回的ack,就误以为没有投递成功,将消息又重新投递一遍。造成消费者重复消费!!!

解决重复消费问题

解决消息重复消费问题,需要在消费端考虑消息的幂等性。

幂等性:对一个接口调用一次和调用多次得到的结果是一样的

解决方案有两套

  1. 使用数据库的唯一约束
  2. 使用redis的setnx

使用数据库的唯一约束保证幂等性

单体架构

分布式

使用雪花算法、Tinyid 等生成唯一ID给消息标识和指纹码,消息入库时作为主键进行保存,因此保证消息唯一性
优点:实现简单
缺点:
1、高并发业务下游数据库有写入性能瓶颈
2、需要
本地ID生成服务,确保外部统一生成ID服务
无法使用时可以进行兜底

**解决方案:**数据库进行分库分表,对消息ID使用算法解析路由到不同的数据库中

Redis原子性

利用redis的setnx命令,天然具有幂等性,从而实现不重复消费

**优点:**性能高,AOF模式数据不丢失
缺点:

  1. 数据同步入库需要考虑到数据库和Redis之间的原子性

  2. 消息不同步入库,Redis定时同步到数据库的策略需要具体设计

**

**

相关推荐
一条泥憨鱼7 小时前
【消息队列】ACK确认了什么:消息队列可靠投递的完整链路
java·后端·kafka·消息队列·rabbitmq
后台模板学习3 天前
Kafka 与 RabbitMQ 在用户认证与权限管理场景
kafka·rabbitmq·linq
装不满的克莱因瓶3 天前
支付订单成功异步MQ权益发放设计和开发
java·架构·系统架构·rabbitmq·硬件架构
千里达景区票务系统3 天前
消息队列选型对比:RabbitMQ vs RocketMQ vs Kafka
kafka·消息队列·rabbitmq·rocketmq
未秃头的程序猿6 天前
@ConditionalOnMissingBean 把我配好的 RabbitMQ 手动 ack 吃掉了
后端·rabbitmq
一条泥憨鱼7 天前
【RabbitMQ】高级篇
java·分布式·rabbitmq·php·ruby
AI你一生一世7 天前
当“暂停“成为架构决策:从签证系统停摆看高可用设计的边界
架构·系统架构·流量控制·幂等性·高可用设计·优雅降级·状态一致性
阳光不锈@9 天前
三大主流消息队列架构设计思想剖析:从 RabbitMQ 到 RocketMQ 的改造实践
kafka·rabbitmq·rocketmq·rabbit改造rocket·去除rabbitmq·rabbitmq改造
catino15 天前
RabbitMQ详解
分布式·rabbitmq·ruby
叶总没有会15 天前
RabbitMQ高级
分布式·rabbitmq