当前位置: 首页 > news >正文

【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中都不会被消费

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啦
在这里插入图片描述
实验结果:
在这里插入图片描述
在这里插入图片描述

http://www.lryc.cn/news/391311.html

相关文章:

  • 深度解码:需求跟踪的艺术与实战应用
  • 数据结构——树的基础概念
  • TimerManager和Timer
  • 手写Spring-MVC之前后置处理器与异常处理、数据库框架
  • 学习笔记(linux高级编程)11
  • vite+vue3+nginx配置统一公共前缀
  • android 国内下载Gradle源
  • mysql8一键安装脚本(linux) 拿走即用
  • C# 开发Winform DataGridView的增删改查实战
  • CentOS 7镜像列表服务下线,还想继续使用该怎么办?
  • 代码随想录训练营第二十八天 122买卖股票的最佳时间II 55跳跃游戏 45跳跃游戏II 1005K次取反后最大化的数组和
  • 在node环境使用MySQL
  • spdlog一个非常好用的C++日志库(四): 源码分析之logger类
  • 逻辑这回事(七)---- 器件基础
  • 中俄汽车产业链合作前景广阔,东方经济论坛助力双边合作与创新
  • 第六篇:精通Docker Compose:打造高效的多容器应用环境
  • C++视觉开发 一.OpenCV环境配置
  • 大数据面试题之Kafka(3)
  • 视频监控平台web客户端的免密查看视频页:在PC浏览器上如何调试手机上的前端网页(PC上的手机浏览器的开发者工具)
  • 力扣2488.统计中位数为 K 的子数组
  • Zabbix对接Elasticsearch(ES)数据库(未成功)
  • 【unity实战】使用Unity实现动作游戏的攻击 连击 轻重攻击和打击感
  • ELK 企业实战7
  • linux 下neo4j的安装
  • Flink ProcessFunction不同流异同及应用场景
  • Matplotlib 文本
  • 信创产业政策,信创测试方面
  • 微信云数据库迁移到unicloud云数据库
  • 快速上手文心一言指令
  • 零基础STM32单片机编程入门(五)FreeRTOS实时操作系统详解及实战含源码视频