消息队列 RabbitMQ[七] RabbitMQ保证消息的可靠性传递(Confirm Return Ack)

目录

消息队列 RabbitMQ[一] RabbitMQ的下载与安装
消息队列 RabbitMQ[二] RabbitMQ可视化管控台创建用户并为用户分配虚拟机
消息队列 RabbitMQ[三] RabbitMQ的HelloWorld工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[四] RabbitMQ的Publish/Subscribe(发布/订阅)工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[五] RabbitMQ的Routing工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[六] RabbitMQ的Topics工作模式(SpringBoot方式与amqp-client方式)
消息队列 RabbitMQ[七] RabbitMQ保证消息的可靠性传递(Confirm Return Ack)
消息队列 RabbitMQ[八] SpringBoot Consumer 限流机制
消息队列 RabbitMQ[九] SpringBoot 设置消息过期时间TTL
消息队列 RabbitMQ[十] SpringBoot 死信队列与延迟队列实现思路


消息流动图:

在这里插入图片描述
如上图可知消息从生产者到消费者要经历三个阶段

  1. 生产者(Producer)发送到交换机(Exchange)
  2. 交换机发送到队列(Queue)
  3. 消费者从队列中取得的数据

那RabbitMQ要怎么保证每一阶段数据都是成功送到了呢??它提供了三种机制来保证消息的可靠性,三种机制分别对应三个阶段

一、Confirm机制

confirm机制能够用来保证消息从生产者到交换机的可靠性,它是一种确认模式,当你开启的时候,RabbitMQ会在生产者发送消息到交换机之后执行一个我们自定义的回调函数,不管生产者发送成功还是发送失败,当生产者发送失败时,我们可以在回调函数中重新发送失败的消息,这样就确保了消息能够从生产者到交换机。

1. 开启Confirm模式

spring:
  rabbitmq:
    ...
    publisher-confirm-type: correlated #开启confirm模式

2. 编写测试代码

	@Test
    public void testTopicsSend(){
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                if (b){
                    System.out.println("发送成功");
                }else {
                    System.out.println("发送失败");
                    // 这里可以写发送失败的处理逻辑,比如重新发送
                }
            }
        });
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.error", "hello rabbitmq");
        rabbitTemplate.convertAndSend("xxx", "log.info", "hello rabbitmq");
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.warning", "hello rabbitmq");
    }

由于第二个交换机名称xxx是瞎写的所以有一个会发送失败
在这里插入图片描述
在这里插入图片描述

二、Return机制

Return机制能够用来保证消息从交换机到队列的可靠性,当你开启的时候,也会执行一个自定义的回调函数,但只有交换机到队列发送失败时才会执行

1. 开启Return模式

spring:
  rabbitmq:
    ...
    publisher-returns: true #开启return机制

2. 编写测试代码

	@Test
    public void testTopicsSend(){
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) {
            	// message 就是发送失败的消息
                System.out.println(new String(message.getBody()));
            }
        });
        // 随便写一个routingkey让它发送失败
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, "log.infoxx.xxx.xx", "hello rabbitmq");
    }

在这里插入图片描述

三、Ack机制

确认机制(Ack)有两种

  • 自动确认:当消费者收到消息之后,立即确认消息,消息就会从MQ中移除
  • 手动确认:等待消费者手动确认之后,消息才会从MQ中移除

确认机制可以解决什么问题呢?

当消费者收到消息之后,如果是自动确认,这时消息已经从MQ中消失了,然而消费者在处理消息时发生了错误导致消息丢失了,这时消息就真的丢失了。当我们使用手动确认时,可以在消息处理之后在确认,这样就算处理错误导致消息丢失也可以再次总MQ中获取到消息

1. 开启手动确认

spring:
  rabbitmq:
    ...
    listener: # 消费者监听设置手动确认
      direct:
        acknowledge-mode: manual
      simple:
        acknowledge-mode: manual

2. 编写消费者代码

	@RabbitListener(queues = "direct_queue1")
    public void listenQueueFanoutQ1(Message message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws IOException {
        try {
            // 业务逻辑处理成功,手动确认
            /*
			 * tag: 消息标记
			 * false: 不是多消息
			 */
            channel.basicAck(tag, false);
        } catch (Exception e) {
            // 处理过程中,发生了异常,不进行确认
            /*
             * tag: 消息标记
             * false: 不是多消息
             * true: 将消息重新返回到队列
             */
            channel.basicNack(tag, false, true);
            // 从MQ中再次获取消息
        }
        System.out.println(new String(message.getBody()));
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值