RabbitMQ(四)重复消费/幂等性和有序性

本文探讨了如何在RabbitMQ中处理消息重复消费问题,通过保证消息唯一性和幂等性,以及实现有序性,确保数据库操作正确性。涉及去重策略、数据库操作(如主键冲突)和使用第三方介质如Redis来维护消费记录。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

幂等性

首先,rabbitMQ并没有为消息的重复消费而设计一种解决方法,这个解决方法需要我们来根据业务自己实现,我整理了几种常见的解决方法。

消息重复发送导致消息被重复消费的场景

  1. 在生产者发送消息给rabbitMQ服务器的时候,有可能因为网络波动等情况,导致生产者收不到rabbitMQ服务器的应答,导致生产者再发送一条消息。

  2. 也是因为网络波动等问题,导致rabbitMQ服务器在向消费者发送消息的时候,没有收到消费者的应答,重复向消费者发生消息。

这两个场景,其实最终都是导致消费者重复消费多次消息,所以在一般的场景下,我们只需要在消费者那里做消息重复消费的保障即可。

解决方法

思路

保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响;保证消息等幂性;

  • 在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;
  • 在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。

这个问题针对业务场景来答分以下几点:

  1. 如果消息是做数据库的insert操作,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。

  2. 如果消息是做redis的set的操作,不用解决,因为无论set几次结果都是一样的,set操作本来就算幂等操作。

  3. 如果以上两种情况还不行,可以准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将<id,message>以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。

有序性

如何保证消息的顺序性?

数据中台服务器A发送 创建学生信息 与 更新学生信息 两条消息。应用服务器B需要接受服务A的消息。接收到创建学生信息的消息就在表里创建一个学生记录。接受到更新学生的消息就更新学生基本信息。

如果B服务器部署了两台,服务A在很短的时间内发送了两条消息,那么服务B可能有一台做创建学生的操作,另外一台做更新学生的操作。那么就有可能发生,更新学生基本信息的操作早于创建学生基本信息的操作。这样的话更新就会失败。

这就牵扯到如何保证消息的顺序性

解决思路

在生产端发送消息的时候,把自己上一条消息ID 记录到放到消息体中。 在消费端接收到消息后,首先检查此消息中的 上一条消息ID属性。如果不存在上一条消息ID属性,那么就正常消费操作。如果成功消费,则将此次消费的消息ID记录到数据库中。  如果存在上一条消息ID属性,那么就先去数据库查看上一条消息是否已经成功被消费。 如果成功被消费,那么就执行正常的业务逻辑。消费并记录本次消息ID。  如果发现上一条消息没有被成功消费,那么可以稍等一下,在程序中执行睡眠X秒的操作。当休眠时间到了以后,再去检查一下上一条消息是否已经被成功消费。如果此时上一条消息仍然没有成功消费,那么就抛出异常,将当前的消息推回原队列,并等待下次重新消费。

在这里插入图片描述

### RabbitMQ 中确保消息按顺序被消费的方法 为了确保 RabbitMQ 中的消息按照发送顺序被消费者处理,有几种最佳实践配置方法可以采用。 #### 使用单线程消费者 当只有一个消费者实例运行时,RabbitMQ 可以保证消息会依次传递给该消费者。这是因为 RabbitMQ 默认情况下是以轮询的方式分发消息到多个竞争性的消费者上;但如果仅有一个活跃的消费者,则不存在并发问题,从而自然保持了消息序列化[^1]。 对于多线程或多进程环境下的单一逻辑单元(比如微服务中的某个业务模块),可以通过限制此部分只启动一个工作线程来接收来自特定队列的信息,以此达到全局有序的效果。 #### 设置 `prefetch_count` 参数 即使在一个应用中有多个消费者实例存在,也可以通过调整消费者的预取计数 (`prefetch_count`) 来控制每个消费者一次最多能获取多少未确认的消息数量。将这个参数设为 1 能够有效地防止不同消费者之间交错处理同一类别的消息,进而维持一定的顺序性[^2]: ```bash channel.basicQos(1); ``` 这段 Java 代码展示了如何设定通道级别的 QoS (Quality of Service),即每次只允许从 broker 获取一条新消息直到前一条已被成功 ACKnowledged 后才会继续拉取消息。 #### 应用层面上实现事务管理或幂等操作 由于网络波动等原因可能导致消息重复投递现象的发生,在某些场景下即便采取上述措施也无法完全杜绝乱序情况。因此建议在应用程序内部加入必要的防重机制——例如基于唯一 ID 的幂等校验,这样即便是相同的内容多次抵达也能得到一致的结果而不影响最终一致性[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值