【RabbitMQ题目踩坑】RabbitMQ设置手动ack后,消息队列有多条消息,只能消 ...

打印 上一主题 下一主题

主题 517|帖子 517|积分 1551

现象:我发送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中都不会被消耗
  1. spring:
  2.   rabbitmq:
  3.     listener:  #这个在测试消费多个消息的时候,不能有下面这些配置,否则只能消费一个消息后就不继续消费了
  4.       simple:
  5.         acknowledge-mode: manual  #指定MQ消费者的确认模式是手动确认模式  这个在消费者者模块配置  设置手动确认(ack)
  6.         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的消息,这样就出现了着实被消耗成功了,但是未被回应的一条消息!!注意这个条件

但是他未被回应:

  1.         之后我将手动ack加上,重启代码,并向MQ中写入3条新的消息,正常按照我们的理解的话,这三天总应该都被消费了吧,但是即使我现在加上了手动ack了,但是由于第一条未ack的消息存在,所以后面的消息也不回被消费:产生了堵塞。现象如下:
复制代码

  1.         遇到这种情况,通过队列purg  message也是无法去掉unacked中的消息的,只能去掉ready中的消息
  2.         我们该怎么将nacked中的消息去掉呢 ?
复制代码
**答案:
****在yml中表明掉手动ack的配置,

这样重启项目后,消息队列里积压的无论是ready大概unnack的消息都会被消耗掉(对于ready未被消耗的,被消耗没题目,但是对于之前消耗成功了但是未被ack的,不能轻易让他被消耗掉,由于我这是在自己实验的过程中,在生产中可不能这样操作,容易导致生产变乱,导致事务的重复消耗,除非你在自己的消耗者端添加着“幂等性校验”,也就是之前被消耗成功的,未ack的不允许重复消耗的校验,这总环境你可以拦住他,所以可以这样搞,否则的话,不可!特殊注意这里)**
我说的方法的实验结果:
前提:0个ready的,1个unacked的,一个total的,表明配置并重启之后:
console中正常被拦住了,而且MQ队列中unacked的也没了 ,OK啦

实验结果:



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南飓风

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表