【RabbitMQ问题踩坑】RabbitMQ设置手动ack后,消息队列有多条消息,只能消费一条,就不继续消费了,这是为什么 ?

现象:我发送5条消息到MQ队列中,同时,我在yml中设置的是需要在代码中手动确认,但是我把代码中的手动ack给关闭了,会出现什么情况?

yml中配置,配置需要在代码中手动去确认消费者消费消息成功,

正常情况 需要在处理完消费的业务逻辑之后,通过channel.basicAck(tag, false);;来给MQ反馈消息已经被消费,也就是手动ack

这种正常的情况表现为: 我发送成功在postman中

其实被消费了已经,所以ready的数目为0,但是MQ还在等待ack回应,我这里注释了,所以在unacked这里会多一个;

此时如果队列中有3条消息的话,也就是ready中存在3条消息,unacked中存在一条,也就是total为4条,那及时其他的消息我修改代码,重新项目了,把注释的手动ack给放开了,那MQ中的情况也不会变,因为如果在代码中设置了消费者需要需要手动ack的话,如果一但存在了未ack的消息【unacked】的消息,那ready中都不会被消费

yaml 复制代码
spring:
  rabbitmq: 
    listener:  #这个在测试消费多个消息的时候,不能有下面这些配置,否则只能消费一个消息后就不继续消费了
      simple:
        acknowledge-mode: manual  #指定MQ消费者的确认模式是手动确认模式  这个在消费者者模块配置  设置手动确认(ack)
        prefetch: 1 #一次只能消费一条消息   这个在消费者者模块配置

有个文献中的解析如下:

Rabbit 中的 channel.basicAck 注释掉,只能消费掉一个消息吗?

在 RabbitMQ 中,当你使用手动消息确认(manual message acknowledgment)模式时, channel.basicAck 方法用于向 RabbitMQ 发送一个确认消息,告知 RabbitMQ 某个消息已经被成功处理。如果你注释掉 channel.basicAck调用,那么 RabbitMQ 将不会收到这个消息已经被处理的确认,并且会根据你的消费者配置来决定如何处理这个消息。

具体行为取决于你的消费者配置中的 autoAck 参数(在某些客户端库中可能称为 noAck或其他名称)

1.如果 autoAck 被设置为 true (也就是不配置 acknowledge-mode: manual,默认是自动ack )

当你从队列中获取一个消息时,RabbitMQ 会立即认为这个消息已经被处理并自动将其从队列中删除。在这种情况下,即使你注释掉 channel.basicAck,RabbitMQ也不会等待任何确认,并且会继续发送下一个消息给消费者。因此,你可以消费掉多个消息,但请注意,如果消费者在处理消息时失败并崩溃,这些消息将会丢失(因为 RabbitMQ 认为它们已经被处理了)。

2.如果 autoAck 被为手动的话:(yml中的 手动ack配置为手动 acknowledge-mode: manual):

当你从队列中获取一个消息时,RabbitMQ 会等待消费者发送一个确认消息(即 channel.basicAck)。如果消费者注释掉了这个确认调用,RabbitMQ将不会收到任何确认,并且会根据你设置的 basicQos 方法中的 prefetchcount 参数来决定是否继续发送下一个消息。

  • 如果 prefetch 大于 1,RabbitMQ 可能会继续发送下一个消息给消费者,但请注意,消费者最多只会同时处理 prefetchcount个未确认的消息,
  • 如果 prefetch设置为1(或未设置,因为默认可能是 0,表示无限制,但这不是推荐的做法)RabbitMQ 将只发送一个消息给消费者,并等待该消息的确认。在这种情况下,如果你注释掉了消费者将只能消费一个消息,并且不会收到下一个消息,直到你发送确认或关闭连channel.basicAck接。

总之,是否只能消费一个消息取决于你的消费者配置(特别是 autoAck和 prefetch )。但是,强烈建议在手动消息确认模式下使用 acknowledge-mode: manual和合理的 prefetch值,以确保消息在处理失败时不会丢失,并控制消费者同时处理的消息数量。

我遇到的问题现象:

我在yml中是添加着需要手动ack的配置的,
操作产生这个问题的过程:

第一次消息将手动ack代码注释后产生了一个nacked的消息,这样就出现了其实被消费成功了,但是未被回应的一条消息!!注意这个条件

但是他未被回应:

复制代码
	之后我将手动ack加上,重启代码,并向MQ中写入3条新的消息,正常按照我们的理解的话,这三天总应该都被消费了吧,但是即使我现在加上了手动ack了,但是由于第一条未ack的消息存在,所以后面的消息也不回被消费:产生了堵塞。现象如下:
复制代码
	遇到这种情况,通过队列purg  message也是无法去掉unacked中的消息的,只能去掉ready中的消息
	我们该怎么将nacked中的消息去掉呢 ?

**答案:

****在yml中注释掉手动ack的配置,

这样重启项目后,消息队列里积压的无论是ready或者unnack的消息都会被消费掉(对于ready未被消费的,被消费没问题,但是对于之前消费成功了但是未被ack的,不能轻易让他被消费掉,因为我这是在自己实验的过程中,在生产中可不能这样操作,容易导致生产事故,导致事务的重复消费,除非你在自己的消费者端添加着"幂等性校验",也就是之前被消费成功的,未ack的不允许重复消费的校验,这总情况你可以拦住他,所以可以这样搞,否则的话,不行!特别注意这里)**

我说的方法的实验效果:

前提:0个ready的,1个unacked的,一个total的,注释配置并重启之后:

console中正常被拦住了,而且MQ队列中unacked的也没了 ,OK啦

实验结果:

相关推荐
J_liaty10 小时前
RabbitMQ面试题终极指南
开发语言·后端·面试·rabbitmq
maozexijr13 小时前
RabbitMQ Exchange Headers类型存在的意义?
分布式·rabbitmq
独自破碎E13 小时前
RabbitMQ的消息确认机制是怎么工作的?
分布式·rabbitmq
maozexijr15 小时前
注解实现rabbitmq消费者和生产者
分布式·rabbitmq
Java 码农2 天前
RabbitMQ集群部署方案及配置指南09
分布式·rabbitmq
论迹2 天前
RabbitMQ
分布式·rabbitmq
Java 码农2 天前
RabbitMQ集群部署方案及配置指南08--电商业务延迟队列定制化方案
大数据·分布式·rabbitmq
Java 码农2 天前
Spring Boot集成RabbitMQ的各种队列使用案例
spring boot·rabbitmq·java-rabbitmq
vb2008112 天前
Ubuntu 系统下 RabbitMQ 作为 MQTT 代理的配置方案
mqtt·rabbitmq
win x2 天前
RabbitMQ快速上手
分布式·rabbitmq