RabbitMQ-生产者可靠性

一、生产者重连

1、概念

由于网络波动导致客户端无法连接上MQ,这是可以开启MQ的失败后重连机制。

注意:

是连接失败的重试,而不是消息发送失败后的重试。

2、开启配置

XML 复制代码
spring:
  rabbitmq:
    template:
      retry:
        enabled: true # 是否启用重试机制
        max-attempts: 3 # 最大重试次数
        initial-interval: 1000ms # 第一次重试的间隔时间
        multiplier: 2 # 重试间隔时间的倍数
        max-interval: 10000ms # 最大重试间隔时间,超过该时间则停止重试

3、重连结果

4、总结

这种超时重连的方式是阻塞式的,后面的代码没办法执行,如果说业务要求比较严格,则需要禁止使用;如果必要使用的情况下,合理设置重连时间。

二、生产者确认

1、概念

生产者将消息发送到MQ之后,MQ会返回一个确认消息给到生产者。有两种方式:

  • Publisher Confirm 消息确认
  • Publisher Return 消息回执

有几种情况产生:

  • 消息投递到MQ,但是路由失败。Publisher Return会返回路由失败,然后返回ACK,告知投递成功。
  • 临时消息投递到MQ,并且入队成功。返回ACK,告知投递成功。
  • 持久消息投递到MQ,并且持久化完成。返回ACK,告知投递成功。
  • 除上述情况外,均会返回NACK,告知投递失败。

2、开启配置

java 复制代码
spring:
  rabbitmq:
    publisher-confirm-type: correlated # 消息确认机制,异步确认
    publisher-returns: true # 消息返回机制

其中,publisher-confirm-type有三种模式:

  • none:不开启确认机制。
  • simple:同步阻塞等待MQ的回执消息,生产者同步等待。
  • correlated:MQ异步回调方式返回回执消息,生产者发送消息之后,继续执行其他任务,MQ收到消息之后,处理完会回执确认信息。首选

3、代码实现

Publisher Return的配置类,这个只需要写一个就行了,但是Publisher Confirm是每次一个消息发送的时候都得写一个:

java 复制代码
@Configuration
public class MqConfirmConfig implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取模板类
        RabbitTemplate rabbitTemplate = applicationContext.getBean(RabbitTemplate.class);
        //创建回调
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returnedMessage) {
                System.out.println("消息返回-----开始");
                System.out.println(returnedMessage.getReplyCode());
                System.out.println(returnedMessage.getExchange());
                System.out.println(returnedMessage.getReplyText());
                System.out.println(returnedMessage.getRoutingKey());
                System.out.println("消息返回-----结束");
            }
        });
    }
}

Publisher Confirm例子:

java 复制代码
public String push9() throws InterruptedException {
        //1、创建CorrelationData,
        // 构造函数需要指定随机id,消息回调时需要使用该id进行匹配
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        //2、添加ConfirmCallback
        correlationData.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            //这个一般不会触发
            @Override
            public void onFailure(Throwable ex) {
                System.out.println("消息回调失败");
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                //交换机收到消息,不管路由是否成功都会收到
                if (result.isAck()) {
                    System.out.println("消息确认成功");
                } else {
                    //交换机错误或者网络错误就会重试
                    System.out.println("消息确认失败,失败原因为:" + result.getReason());
                }
            }
        });

        String topicExchange = "topicExchange";
        rabbitTemplate.convertAndSend(topicExchange, "cq.hh","重庆串串也好吃",correlationData);
        Thread.sleep(4000);
        return "success";
    }

rabbitTemplate.convertAndSend(topicExchange, "cq.hh","重庆串串也好吃",correlationData); 加粗的这个绑定不要忘记了,我就是忘记了这个,一直找不到原因。

4、结果测试

(1)如果是交换机写错了,就说明交换机没有收到消息,所以ACK应答是false:

(2)交换机收到消息,路由失败;会显示交换机收到消息了,ACK成功,但是Publisher Return会告诉你相关信息,比如没有路由:NO_ROUTE

(3)消息接收成功,路由成功的场景,直接告诉ACK成功:

相关推荐
都说名字长不会被发现15 小时前
分布式场景下的数据竞争问题与解决方案
分布式·乐观锁·悲观锁·redission·redis 分布式锁·数据版本
甘露s15 小时前
分布式与可重入性的一些问题
分布式
juniperhan15 小时前
Flink 系列第 3 篇:核心概念精讲|分布式缓存 + 重启策略 + 并行度 底层原理 + 代码实战 + 生产规范
大数据·分布式·缓存·flink
想你依然心痛15 小时前
HarmonyOS 5.0 IoT开发实战:构建分布式智能设备控制中枢与边缘计算网关
分布式·物联网·harmonyos
lifallen15 小时前
如何保证 Kafka 的消息顺序性?
java·大数据·分布式·kafka
橙露15 小时前
大数据处理:PySpark 入门与分布式数据分析实战
分布式·数据挖掘·数据分析
时光追逐者15 小时前
分享四款开源且实用的 Kafka 管理工具
分布式·kafka·开源
Rick199315 小时前
rabbitmq, rocketmq, kafka这三种消息如何分别保住可靠性,顺序性,以及应用场景?
kafka·rabbitmq·rocketmq
IT枫斗者16 小时前
AI Agent 设计模式全景解析:从单体智能到分布式协作的架构演进
人工智能·redis·分布式·算法·spring·缓存·设计模式
☞遠航☜18 小时前
kafka快速上手
分布式·kafka·linq