发布确认和高级发布确认的理解

发布确认

amqp-client自带的发布确认机制,这里只讲异步确认,同步确认请转接rabbitMQ官网
https://www.rabbitmq.com/confirms.html
即channel.confirmSelect()方法,使用后会开启发布确认机制,增加确认监听器,内置成功和失败的回调方法,如下:

经过测试,得出以下几点总结:
1.当publish发布消息时,如果exchange交换机不存在,控制台会报错无法找到交换机,而不会调用监听器
2.当routingKey不存在时,不会导致监听器消息确认失败,由此可知,消息确认是在交换机
3.ConfirmCallback第二个参数表示是否为批量,回调函数会自动选择批处理或者单个处理,所以有时候需要判断一下

以上为普通确认发布的测试总结,因为普通确认发布有一些弊端,所以有了高级确认发布,
普通确认发布也可以对队列进行监控,使用returnedListener监听器
//异步确认
    public static void syncConfirm() throws Exception {
        //获取信道
        Channel channel = RabbitMqUtil.getChannel();

        //开启发布确认
        channel.confirmSelect();

        //声明队列
        //durable = true 队列持久化
        channel.queueDeclare(Confirm_Queue_Name,true,false,false,null);

        /**
         * 线程安全有序的一个哈希表 适用于高并发的情况下
         *1.轻松的将序号和消息进行关联map
         *2.轻松的批量删除条目 只要给到序号
         * 3.支持高并发
         * */
        ConcurrentSkipListMap<Long,String> outStandingConfirms = new ConcurrentSkipListMap<>();

        /**
         * 准备消息的监听器,监听哪些消息成功了,哪些消息失败了
         * */
        //消息成功监听器
        /**
         * 参数
         * 1.消息的标记
         * 2.是否为批量
         * 只有当交换机存在时才会调用
         * 有可能批量有可能不批量
         * */
        ConfirmCallback ackCallback = (deliveryTag, multiple) -> {
            if (multiple){
                //删除已经确认的消息,剩下的就是未确认的消息
                ConcurrentNavigableMap<Long, String> confirmed = outStandingConfirms.headMap(deliveryTag);
                confirmed.clear();
                System.out.println("批量确认的消息:"+deliveryTag);
            }else {
                outStandingConfirms.remove(deliveryTag);
                System.out.println("确认的消息:"+deliveryTag);
            }
        };

        //消息失败回调函数,发送过去后没有接受到交换机的确认信息,在等待交换机确认信息的时候交换机宕机
        ConfirmCallback nackCallback = (deliveryTag, multiple) -> {
            String message = outStandingConfirms.get(deliveryTag);
            System.out.println("未确认的消息:"+message);
        };
        /**
         * 1.监听哪些消息成功了
         * 2.监听哪些消息失败了
         * */
        channel.addConfirmListener(ackCallback,nackCallback);
//        channel.addConfirmListener(new ConfirmListener() {
//            @Override
//            public void handleAck(long deliveryTag, boolean multiple) throws IOException {
//                if (true) {
//                    System.out.println("message"+deliveryTag+"到达交换机");
//                }
//            }
//
//            @Override
//            public void handleNack(long deliveryTag, boolean multiple) throws IOException {
//                if (true) {
//                    System.out.println("message"+deliveryTag+"没有到达交换机");
//                }
//            }
//        });

        //开始时间
        long beginTime = System.currentTimeMillis();
        //批量发送消息
        for (int i = 0;i<10;i++){
            String message = i+"";
            channel.basicPublish("",Confirm_Queue_Name,null,message.getBytes(StandardCharsets.UTF_8));
            //记录所有消息
            outStandingConfirms.put(channel.getNextPublishSeqNo(),message);
        }

        //结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("发布"+10+"个批量消息共用时:"+(endTime-beginTime));

    }

高级发布确认

springboot整合的rabbitMQ实现了对消息到达交换机的监听,如果交换机不存在也会调用回调方法,需要在配置文件中开启确认发布,如果要监听消息路由到队列是否成功,需要在配置文件中配置消息回退机制

以上机制主要是用来防止消息的丢失,消息持久化不太好测试,猜测,回调函数会在消息持久化之后执行,如果消息回退,可以在消息回退方法中 对消息进行重试,redis记录重试次数,代码就不演示了,只演示配置文件和回调方法

#启用交换机确认回调接口
spring.rabbitmq.publisher-confirm-type=correlated
#开启发布回退
spring.rabbitmq.publisher-returns=true
package com.zwj.springbootrabbitmq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author zwj
 * @date 2022/1/10 - 20:32
 */
@Slf4j
@Component
public class MyCallBack implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback{


    @Autowired
    private RabbitTemplate rabbitTemplate;

    //注入   将实现类set到RabbitTemplate中的ConfirmCallback参数中
    @PostConstruct //对象加载完依赖注入后执行
    public void init(){
        //注入
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    /**
     * 交换机回调方法
     * 1.发消息 交换机接收到了 回调
     *      1.1 correlationData 保存回调信息的ID及相关信息
     *      1.2 交换机收到信息 ack = true
     *      1.3 cause null
     * 2.发消息 交换机接收失败了 回调
     *      2.1 correlationData 保存回调信息的ID及相关信息
     *      2.2 交换机收到消息 ack = false
     *      2.3 cause 失败的原因
     * */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack){
            log.info("交换机已经收到了id为:{}的消息",id);
        }else {
            log.info("交换机还未收到id为:{}的消息,由于原因:{}",id,cause);
        }

    }

    //只有在当消息传递过程中不可达目的地是将消息返回给生产者
    //只有不可达目的地的时候才进行回退

    @Override
    public void returnedMessage(ReturnedMessage returned) {
        log.error("消息{},被交换机{}退回,退回原因:{},路由key:{}",
                new String(returned.getMessage().getBody()),returned.getExchange(),returned.getReplyText(),
                returned.getRoutingKey());
    }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值