RabbitMQ---重新投递到不存在的exchange 导致MQ无法提供服务


本文环境:springboot 1.5.8.RELEASE + amqp-client 4.0.3.jar

记一个很神奇的bug。

场景:开启生产者确认模式,指定了自定义ConfirmCallback实现类。

尝试投递到不存在的exchange,成功回调confim接口,随后再次重发该信息。

但意外的是,不止没有回调confirm接口。还导致整个rabbitMQ卡死,发送消息到其他交换机一样无作用。

原因:

上述操作:“尝试投递到不存在的exchange”,会产生一个ERROR:

ERROR org.springframework.amqp.rabbit.connection.CachingConnectionFactory - Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'noexist' in vhost '/', class-id=60, method-id=40)

这个error,不管是否开启了生产者确认模式,都是会触发的。

但在实现了生产者确认模式后,会在confirm接口回调完毕之后再触发

但因为在confirm回调中,又进行了重发消息的操作。

这样就形成了一个死循环

  • confirm不完成,error就不触发
  • error不触发,RabbitMQ就不能提供服务
  • RabbitMQ不提供服务,重发消息就无法完成,阻塞在那里
  • 重发消息不完成,confirm就不能完成

禁止套娃

因此即使是发送到其他存在的交换机的信息,也会因为RabbitMQ无法提供服务,而阻塞。

但需要注意的是,其他任务是可以正常进行的(CPU没资源之类的除外)。辅助跑了个定时任务,是可以正常输出的。


解决办法:
很简单。就是不要在confirm里面重新发送,交给延迟队列或者定时任务完成,就解决了


直观的感受一下:

代码:

rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
     
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
     
                System.out.println("---------触发confirm-----------");
                mqSender.reSendMiaoshaMessage(miaoshaMessage, 
                System.out.println("----------confirm触发完成----------");
            }
        });
public void reSendMiaoshaMessage(MiaoshaMessage mm,CorrelationData correlationData) {
     
        System.out.println("重发消息");
        String msg = RedisService.beanToString(mm);
        rabbitTemplate.convertAndSend("notExist", MQConfig.MIAOSHA_ROUTING_KEY, msg, correlationData);
        System.out.println("重发消息完成");
    }

控制台输出:

RabbitMQ---重新投递到不存在的exchange 导致MQ无法提供服务_第1张图片


这么神奇的bug,估计没几个人遇到,所以网上找过一轮都没有蛛丝马迹。

mark一下,能遇上这个bug的,感觉都是有缘人……


本文完,有误欢迎指出

你可能感兴趣的:(bug,笔记,java,rabbitmq,bug)