RabbitMq报错reply-code=406 reply-text=PRECONDITION_FAILED解决

 更新时间:2022年12月26日 11:29:05   作者:刨红薯的小羊竿尔  
这篇文章主要为大家介绍了RabbitMq报错reply-code=406 reply-text=PRECONDITION_FAILED分析解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一、检查配置是否正确

今天看生产日志发现了很多的RabbitMq报错:reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80,全都是异常之后重复消费,重复报错。

unknown delivery tag 1-参考rabbitMQ的tag机制可知这条消息已经完成了消费;那么出现这个原因是配置不对了。

首先排查SimpleRabbitListenerContainerFactory是否加上手动ack

private SimpleRabbitListenerContainerFactory getSimpleRabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
    factory.setConnectionFactory(connectionFactory);
    //使用jackson进行消息序列与反序列
    factory.setMessageConverter(new Jackson2JsonMessageConverter());
    factory.setAcknowledgeMode(AcknowledgeMode.MANUAL); // 开启手动 ack
    return factory;
}

Jackson2JsonMessageConverter是rabbitmq 对java对象json序列化的支持,在发送消息时,会先将自定义的消息类序列化成json格式,再转成byte构造 Message,rabbitmq的ack就被设置为自动提交;需要手动开启ack,没得问题:factory.setAcknowledgeMode(AcknowledgeMode.MANUAL)。

其次检查配置文件,配置文件设置为手动ack

spring.rabbitmq.listener.direct.acknowledge-mode=manual

rabbitmq:
  host: 127.0.0.1
  port: 5672
  username: guest
  password: guest
  ###开启消息确认机制 confirms
  virtual-host: /
  publisher-confirms: true
  publisher-returns: true
  #rabbitmq配置加上手动应答
  listener:
      simple:
        acknowledge-mode: manual

二、rabbitmq消息重回队列,回到队尾

当出现异常时,我们需要把这个消息回滚到消息队列,有两种方式:

  • ack返回false,并重新回到队列channel.basicNack channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
  • 拒绝消息channel.basicReject channel.basicReject(message.getMessageProperties().getDeliveryTag(), true)

但是环境中的实际情况是,当消息回滚到消息队列时,这条消息不会回到队列尾部,而是仍是在队列头部,这时消费者会立马又接收到这条消息进行处理,接着抛出异常,进行回滚,如此反复进行。这种情况会导致消息队列处理出现阻塞,消息堆积,导致正常消息也无法消费

对于消息回滚到消息队列,我们希望方式是出现异常的消息到达消息队列尾部,这样既保证消息不会丢失,又保证了正常业务的进行

因此我们采取的解决方案是,将消息先进行应答,这时消息队列会删除该消息,同时再次发送该消息到消息队列,这时就实现了错误消息进行消息队列尾部的方案。

具体方案为:

//手动进行应答
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
//重新发送消息到队尾
channel.basicPublish(message.getMessageProperties().getReceivedExchange(),
message.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,
JSON.toJSONBytes(new Object()));

三、消息体本身有误

如果一个消息体本身有误,会导致该消息体,一直无法进行处理,而服务器中刷出大量无用日志

解决这个问题可以采取两种方案:

1、对于日常细致处理,分清哪些是可以恢复的异常,哪些是不可以恢复的异常。对于可以恢复的异常我们采取第三条中的解决方案,对于不可以处理的异常,我们采用记录日志,直接丢弃该消息方案。

2、对每条消息进行标记,记录每条消息的处理次数,当一条消息,多次处理仍不能成功时,处理次数到达我们设置的值时,我们就丢弃该消息,但需要记录详细的日志。

消息监听内的异常处理有两种方式:

1、内部catch后直接处理,然后使用channel对消息进行确认

2、配置RepublishMessageRecoverer将处理异常的消息发送到指定队列专门处理或记录。监听的方法内抛出异常貌似没有太大用处。因为抛出异常就算是重试也非常有可能会继续出现异常,当重试次数完了之后消息就只有重启应用才能接收到了,很有可能导致消息消费不及时。当然可以配置RepublishMessageRecoverer来解决,但是万一RepublishMessageRecoverer发送失败了呢。那就可能造成消息消费不及时了。所以即使需要将处理出现异常的消息统一放到另外队列去处理,个人建议两种方式:

  • catch异常后,手动发送到指定队列,然后使用channel给rabbitmq确认消息已消费
  • 给Queue绑定死信队列,使用nack(requque为false)确认消息消费失败

以上就是RabbitMq报错reply-code=406 reply-text=PRECONDITION_FAILED解决的详细内容,更多关于RabbitMq reply报错解决的资料请关注脚本之家其它相关文章!

相关文章

  • JavaWeb实现文件上传下载功能实例详解

    JavaWeb实现文件上传下载功能实例详解

    这篇文章主要介绍了JavaWeb中的文件上传和下载功能的实现,在开发中,文件上传和下载功能是非常常用的功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • 详解Java线程池的使用(7种创建方法)

    详解Java线程池的使用(7种创建方法)

    这篇文章主要介绍了详解Java线程池的使用(7种创建方法),线程池的创建⽅式总共包含7种,其中6种是通过Executors创建的,1种是通过ThreadPoolExecutor创建的,今天我们就来详细说一下
    2023-03-03
  • spring boot发简单文本邮件案例

    spring boot发简单文本邮件案例

    这篇文章主要介绍了spring boot发简单文本邮件案例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • IDEA 非常重要的一些设置项(一连串的问题差点让我重新用回 Eclipse)

    IDEA 非常重要的一些设置项(一连串的问题差点让我重新用回 Eclipse)

    这篇文章主要介绍了IDEA 非常重要的一些设置项(一连串的问题差点让我重新用回 Eclipse),本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • java数据结构和算法学习之汉诺塔示例

    java数据结构和算法学习之汉诺塔示例

    这篇文章主要介绍了java数据结构和算法中的汉诺塔示例,需要的朋友可以参考下
    2014-02-02
  • Spring框架依赖注入方法示例

    Spring框架依赖注入方法示例

    这篇文章主要介绍了Spring框架依赖注入方法示例,分享了三种方法示例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java实现简单的分页功能

    Java实现简单的分页功能

    这篇文章主要为大家详细介绍了Java实现简单的分页功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • java堆排序原理与实现方法分析

    java堆排序原理与实现方法分析

    这篇文章主要介绍了java堆排序原理与实现方法,结合实例形式分析了java堆排序的相关原理、实现方法与操作注意事项,需要的朋友可以参考下
    2018-12-12
  • 四个Java必须知道的负载均衡算法分享

    四个Java必须知道的负载均衡算法分享

    我们在设计系统的时候,为了系统的高扩展性,会创建无状态的系统。但是,要使系统具有更好的可扩展性,除了无状态设计之外,还要考虑采用什么负载均衡算法,本文就带领大家认识以下常见的4种负载均衡算法
    2023-01-01
  • SpringBoot JVM参数调优方式

    SpringBoot JVM参数调优方式

    这篇文章主要介绍了SpringBoot JVM参数调优方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09

最新评论