RabbitMQ消费端ACK NACK及重回队列机制详解

 更新时间:2022年12月26日 11:54:12   作者:刨红薯的小羊竿尔  
这篇文章主要为大家介绍了RabbitMQ消费端ACK NACK及重回队列机制详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

ACK和NACK

当我们使用RabbitMQ时用于网络异常,业务处理异常或者业务错误导致消息无法立即消费时,在这种情况下,传输中的信息将无法正常投递——它们需要被重新投递。Acknowledgements机制让服务器和客户端知道何时需要重新投递。

当设置autoACK=false 时,就可以使用手工ACK。 其实手工方式包括了手工ACK、手工NACK。

  • 手工 ACK 时,会发送给Broker一个应答,代表消息处理成功,Broker就可回送响应给Pro;
  • NACK 则表示消息处理失败,如果设置了重回队列,Broker端就会将没有成功处理的消息重新发送。

使用方式

1、basicNack

Consumer消费时,若由于业务异常,可手工 NACK 记录日志,然后进行补偿: basic.nack方法为不确认deliveryTag对应的消息,第二个参数是否应用于多消息第三个参数是否requeue,如果requeue 参数设置为true ,则RabbitMQ 会重新将这条消息存入队列,以便可以发送给下一个订阅的消费者, 如果requeue 参数设置为false ,则RabbitMQ立即会把消息从队列中移除,而不会把它发送给新的消费者。与basic.reject区别就是同时支持多个消息,可以nack该消费者先前接收未ack的所有消息。nack后的消息也会被自己消费到。

multiple 参数设置为false 则表示拒绝编号为deliveryTag的这一条消息,这时候basicNack 和basicReject 方法一样;multiple 参数设置为true 则表示拒绝deliveryTag 编号之前所有未被当前消费者确认的消息。

  • 参数1: 消息
  • 参数2: 是否应用于多消息
  • 参数3: 是否重新放回队列,否则丢弃或者进入死信队列
void basicNack(long deliveryTag, boolean multiple, boolean requeue)

2、basicAck

如果由于服务器宕机等严重问题,就需要手工 ACK 保障Con消费成功:deliveryTag : 每次接收消息+1,可以做此消息处理通道的名字。

void basicAck(long deliveryTag, boolean multiple)

3、basicReject

basic.Reject拒绝deliveryTag对应的消息,第二个参数是否requeue,true则重新入队列,否则丢弃或者进入死信队列。该方法reject后,该消费者还是会消费到该条被reject的消息。reject一次只能拒绝一条消息,如果想要批量拒绝消息,则可以使用Basic.Nack 这个命令。

  • 参数1: 消息
  • 参数2: 是否重新放回队列,否则丢弃或者进入死信队列
void basicReject(long deliveryTag, boolean requeue);

4、basicRecover

basic.recover是否恢复消息到队列,参数是是否requeue,true则重新入队列,并且尽可能的将之前recover的消息投递给其他消费者消费,而不是自己再次消费。false则消息会重新被投递给自己。

channel.basicRecover(true);

消费端的重回队列

重回队列针对没有处理成功的消息,将消息重新投递给Broker。
重回队列会把消费失败的消息重新添加到队列尾端,供Consumer重新消费。
一般在实际应用中,都会关闭重回队列,即设置为false。

在确认ack后再把消息通过basicPublish到队列尾部,防止正常消息堆积。

channel.basicPublish(message.getMessageProperties().getReceivedExchange(),message.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,JSON.toJSONBytes(new Object()));

实际运用

@RabbitListener(queues = "${rabbitmq.one-queue}",
        containerFactory = "rabbitListenerContainerFactory")
@RabbitHandler
public void doRmOnduty(Message message, Channel channel) {
    try {
        String body = new String(message.getBody());
        //log.info("消息处理:{}",body);
    } catch (Exception e) {
        //消费异常,设置重回队列
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
    } finally {
        //最终确认消息消费成功
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

ACK机制可以保证Con拉取到了消息,若处理失败了,则队列中还有这个消息,仍然可以给Con处理。ack机制是 Con 告诉 Broker 当前消息是否成功消费,至于 Broker 如何处理 NACK,取决于 Con 是否设置了 requeue:如果 requeue=false, 则NACK 后 Broker 还是会删除消息的。

但一般处理消息失败都是因为代码逻辑出bug,即使队列中后来仍然保留该消息,然后再给Con消费,依旧报错。 当然,若一台机器宕机,消息还有,还可以给另外机器消费,这种情景下 ACK 很有用。

如果不使用 ACK 机制,直接把出错消息存库,便于日后查bug或重新执行。

以上就是RabbitMQ消费端ACK NACK及重回队列机制详解的详细内容,更多关于RabbitMQ消费端ACK NACK的资料请关注脚本之家其它相关文章!

相关文章

  • javaNIO中关于ByteBuffer的用法

    javaNIO中关于ByteBuffer的用法

    这篇文章主要介绍了javaNIO中关于ByteBuffer的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • java split()使用方法解析

    java split()使用方法解析

    这篇文章主要介绍了java split()使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 详谈jvm--Java中init和clinit的区别

    详谈jvm--Java中init和clinit的区别

    下面小编就为大家带来一篇详谈jvm--Java中init和clinit的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java通用Mapper UUID简单示例

    Java通用Mapper UUID简单示例

    今天小编就为大家分享一篇关于Java通用Mapper UUID简单示例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • Java虚拟机启动过程探索

    Java虚拟机启动过程探索

    当我们在编写Java应用的时候,很少会注意Java程序是如何被运行的,如何被操作系统管理和调度的,带着好奇心,探索一下Java虚拟机启动过程
    2022-05-05
  • Java压缩解压缩工具类

    Java压缩解压缩工具类

    这篇文章主要为大家详细介绍了Java压缩解压缩工具类,如何压缩单个文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 详解Java编程中的策略模式

    详解Java编程中的策略模式

    这篇文章主要介绍了详解Java编程中的策略模式,以及用策略模式来分析源码等内容,需要的朋友可以参考下
    2015-08-08
  • SpringBoot RestTemplate 简单包装解析

    SpringBoot RestTemplate 简单包装解析

    这篇文章主要介绍了SpringBoot RestTemplate 简单包装解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Java使用ANTLR4对Lua脚本语法校验详解

    Java使用ANTLR4对Lua脚本语法校验详解

    ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本语法校验吧
    2025-04-04
  • java类实现日期的时间差的实例讲解

    java类实现日期的时间差的实例讲解

    在本篇文章里小编给大家整理的是一篇关于java类实现日期的时间差的实例讲解内容,有兴趣的朋友们可以学习下。
    2021-01-01

最新评论