RabbitMQ高级特性

消息的可靠投递

在这里插入图片描述

confirm 确认模式(针对生产者)

确认模式:
步骤:
1. 确认模式开启: publisher-confirm-type: correlated
2. 在rabbitTemplate定义ConfirmCallBack回调函数

首先是 开启确认模式:
在这里插入图片描述
然后是设置交换机和队列:

@Configuration
public class RabbitMQConfirmConfig {

    public static final String EXCHANGE_NAME = "test_exchange_confirm";
    public static final String QUEUE_NAME = "test_queue_confirm";

    //1.交换机
    @Bean("bootExchange")
    public Exchange bootExchange(){

        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }


    //2.Queue 队列
    @Bean("bootQueue")
    public Queue bootQueue(){
        return QueueBuilder.durable(QUEUE_NAME).build();
    }

    //3. 队列和交互机绑定关系 Binding
    /*
        1. 知道哪个队列
        2. 知道哪个交换机
        3. routing key
     */
    @Bean
    public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange){
        return BindingBuilder
                .bind(queue).to(exchange).with("confirm").noargs();
    }

最后测试代码:

   //1.注入RabbitTemplate
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Test
    public void testConfirm() {

        //2. 定义回调
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             *
             * @param correlationData 相关配置信息
             * @param ack   exchange交换机 是否成功收到了消息。true 成功,false代表失败
             * @param cause 失败原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                System.out.println("confirm方法被执行了....");
                if (ack) {
                    //接收成功
                    System.out.println("接收成功消息" + cause);
                } else {
                    //接收失败
                    System.out.println("接收失败消息" + cause);
                    //做一些处理,让消息再次发送。
                }
            }
        });

        //3. 发送消息
        rabbitTemplate.convertAndSend("test_exchange_confirm111", "confirm", "message confirm....");
    }

return 退回模式(针对生产者)

 /**
     * 回退模式: 当消息发送给Exchange后,Exchange路由到Queue失败是 才会执行 ReturnCallBack
     * 步骤:
     * 1. 开启回退模式:publisher-returns="true"
     * 2. 设置ReturnCallBack
     * 3. 设置Exchange处理消息的模式:
     *		 1. 如果消息没有路由到Queue,则丢弃消息(默认)
     * 		2. 如果消息没有路由到Queue,返回给消息发送方ReturnCallBack
     */

首先是yaml:
在这里插入图片描述
交换机和队列用上一个案列即可。

测试代码:

//1.注入RabbitTemplate
    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Test
    public void testReturn() {

        //设置交换机处理失败消息的模式
        rabbitTemplate.setMandatory(true);

        //2.设置ReturnCallBack
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             *
             * @param message   消息对象
             * @param replyCode 错误码
             * @param replyText 错误信息
             * @param exchange  交换机
             * @param routingKey 路由键
             */
            @Override
            public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
                System.out.println("return 执行了....");

                System.out.println(message);
                System.out.println(replyCode);
                System.out.println(replyText);
                System.out.println(exchange);
                System.out.println(routingKey);

                //处理
            }
        });


        //3. 发送消息
        rabbitTemplate.convertAndSend("test_exchange_confirm", "confirm", "message confirm....");
    }

总结:

在这里插入图片描述

Consumer Ack(针对消费者)

在这里插入图片描述

手动确认:

代码:

@Autowired
    private RabbitTemplate rabbitTemplate;


    @Test
    public void testack(){
       while (true){

       }
    }
    @RabbitListener(queues = "test_queue_confirm",ackMode ="MANUAL" )
    public void listener(Message message, Channel channel) throws Exception {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();

        try {
            //1.接收转换消息
            System.out.println(new String(message.getBody()));

            //2. 处理业务逻辑
            System.out.println("处理业务逻辑...");
//            int i = 3/0;//出现错误
            //3. 手动签收
            channel.basicAck(deliveryTag,false);
        } catch (Exception e) {
            //e.printStackTrace();

            //4.拒绝签收
            /*
            第三个参数:requeue:重回队列。如果设置为true,则消息重新回到queue,broker会重新发送该消息给消费端
             */
            channel.basicNack(deliveryTag,true,true);
            //channel.basicReject(deliveryTag,true);
        }
    }
Multiple 的解释

手动应答的好处是可以批量应答并且减少网络拥堵
multiple 的 true 和 false 代表不同意思
true 代表批量应答 channel 上未应答的消息
比如说 channel 上有传送 tag 的消息 5,6,7,8 当前 tag 是 8 那么此时
5-8 的这些还未应答的消息都会被确认收到消息应答
false 同上面相比
只会应答 tag=8 的消息 5,6,7 这三个消息依然不会被确认收到消息应答
在这里插入图片描述

Ack小结:

在这里插入图片描述

消息可靠性总结

在这里插入图片描述

消费端限流

在这里插入图片描述

代码:

只需要改这里的设置即可,其他的不用变
在这里插入图片描述
测试发送10条,消费者一直不手动应答,看看能持续接受那几条
在这里插入图片描述

小结:

在这里插入图片描述

TTL

在这里插入图片描述

队列里面统一过期

代码:

只需要在创建队列的时候添加这个参数即可:
在这里插入图片描述

单独消息过期时间:

代码:

// 消息后处理对象,设置一些消息的参数信息
        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {

            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //1.设置message的信息
                message.getMessageProperties().setExpiration("5000");//消息的过期时间
                //2.返回该消息
                return message;
            }
        };
        //消息单独过期
        rabbitTemplate.convertAndSend("test_exchange_ttl", "ttl.hehe", "message ttl....",messagePostProcessor);

注意!!:

消息过期后,只有消息在队列顶端,才会判断其是否过期(移除掉)
解释:
比如下面的代码 则不会被过期: 因为rabbitmq不会取 遍历找寻那个消息要过期了,那样会很慢,所以他直接只看第一个设置有没有过期时间,有就把他删除了,没有就算了。
在这里插入图片描述

死信队列

基础架构图:

在这里插入图片描述
在这里插入图片描述

产生原因:

在这里插入图片描述

代码实现:

  死信队列:
            1. 声明正常的队列(test_queue_dlx)和交换机(test_exchange_dlx)
            2. 声明死信队列(queue_dlx)和死信交换机(exchange_dlx)
            3. 正常队列绑定死信交换机
                设置两个参数:
                    * x-dead-letter-exchange:死信交换机名称
                    * x-dead-letter-routing-key:发送给死信交换机的routingkey

逻辑代码:

@Configuration
public class RabbitMQDeadConfig {

    public static final String EXCHANGE_NAME = "test_exchange_dlx";
    public static final String QUEUE_NAME = "test_queue_dlx";
    public static final String DEAD_EXCHANGE_NAME = "exchange_dlx";
    public static final String DEAD_QUEUE_NAME = "queue_dlx";

    //1.正常交换机
    @Bean("bootExchange")
    public Exchange bootExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }

    //2.正常Queue 队列
    @Bean("bootQueue")
    public Queue bootQueue(){

        //还有和死刑交换机进行绑定
        return QueueBuilder.durable(QUEUE_NAME)
                .ttl(1000*10)  //设置ttl时间 模拟死刑
                .deadLetterExchange(DEAD_EXCHANGE_NAME) //绑定死刑交换机
                .deadLetterRoutingKey("#.dlx.#")  //设置死刑key
                .build();
    }

    //3. 队列和交互机绑定关系 Binding
    /*
        1. 知道哪个队列
        2. 知道哪个交换机
        3. routing key
     */
    @Bean
    public Binding bindQueueExchange(@Qualifier("bootQueue") Queue queue, @Qualifier("bootExchange") Exchange exchange){
        return BindingBuilder
                .bind(queue).to(exchange).with("test.#").noargs();
    }


    //1.死刑交换机
    @Bean("deadExchange")
    public Exchange deadExchange(){
        return ExchangeBuilder.topicExchange(DEAD_EXCHANGE_NAME).durable(true).build();
    }

    //2.死刑Queue 队列
    @Bean("deadQueue")
    public Queue deadQueue(){
        //设置ttl时间 模拟死刑
        return QueueBuilder.durable(DEAD_QUEUE_NAME).build();
    }

    //3. 死刑队列和死刑机绑定关系 Binding
    /*
        1. 知道哪个队列
        2. 知道哪个交换机
        3. routing key
     */
    @Bean
    public Binding binddeadQueueExchange(@Qualifier("deadQueue") Queue queue, @Qualifier("deadExchange") Exchange exchange){
        return BindingBuilder
                .bind(queue).to(exchange).with("#.dlx.#").noargs();
    }


}

测试代码:

  for (int i = 0; i < 20; i++) {
            rabbitTemplate.convertAndSend("test_exchange_dlx","test.dlx.haha","我是一条消息,我会死吗?");
        }

总结:

在这里插入图片描述

!!延迟队列:

应用场景:下订单30分钟之内需要确认这种。
延迟队列:TTL+死性队列
在这里插入图片描述

代码:

就是上面的TTl+死刑队列相组合即可完成

总结:

在这里插入图片描述

应用问题

以下问题主要是思路的讲解 建议看视频很短的:
视频链接

消息可靠性保障–消息补偿

主要是 确保消息能够百分百传送到,
在这里插入图片描述

消息幂等性保障

在这里插入图片描述
在这里插入图片描述

集群问题

免费资料下载

补充:

镜像队列:
搭建集群,一般可能主节点挂了,他队列里面的信息,从节点就无法访问了,于是需要搭建镜像队列
负载均衡-HAProxy
集群搭建好了,我们向哪个IP写代码比较合适嘞?所以这时候需要一个管理所有的IP的插件,我们向插件写,他自动取分配可用的IP地址。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值