消息队列(六)——RabbitMQ高级

RabbitMQ高级

一、过期时间TTL(Time-To-Live)
过期时间TTL表示可以对消息设置预期的时间,在这个时间段内都可以被消费者获取,过期则自动删除(过期的称为dead message被投递到死信队列)
1、通过队列属性设置,队列中所有消息都有相同的过期时间
2、对消息进行单独设置,每条消息TTL可以不同
如果两种方法一起使用就看谁的TTL比较短,以短的为准

1、设置队列属性
通过队列属性设置消息TTL的方法是在queue.declare方法中加入x-message-ttl参数,单位 为ms.

//声明队列
@Bean("itemQueue")
public Queue itemQueue(){
    Map<String,Object> map = new HashMap<>();
    //设置队列的过期时间
    map.put("x-message-ttl",6000);
    return new Queue("itemQueue",true,false,false,map);
}

会看见队列有个TTL
在这里插入图片描述

2、单独设置消息

二、死信队列
死信队列DLX:当业务处理失败(比如抛异常并且达到了retry的上限),就会将消息重新投递到另一个Exchange(Dead Letter Exchanges),该Exchange再根据routingkey重定向另一个队列,在这个队列重新处理该消息。

来自一个队列的消息可以被当做‘死信’,即被重新发不到另一个“exchange”去,这样的情况有
1、消息被拒绝(
2、消息过期TTL
3、队列长度达到最大
在这里插入图片描述
代码
application.yml

spring:
# rabbitMQ配置
  rabbitmq:
    host: 39.97.123.123
    port: 5672
    virtual-host: my_vhost  #虚拟主机(相当于mysql的数据库库名)
    username: admin
    password: admin

    # 死信队列必要配置
    listener:
      simple:
        retry:
          enabled: true   #允许消息消费失败重试
          max-attempts: 3 #消息消费最多允许3次
          initial-interval: 1000  #消息多次消费间隔1s
        default-requeue-rejected: false #设置为false,会丢弃消息或者重新发布到死信队列

RabbitDeadLetterConfig

package com.jinv.studentinfo.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: jinv
 * @CreateTime: 2020-06-12 21:53
 * @Description: RabbitMQ死信队列配置类
 */
@Configuration
public class RabbitDeadLetterConfig {
    public static final String DEAD_LETTER_EXCHANGE =  "DLT_EXCHANGE";
    public static final String DEAD_LETTER_QUEUE="DLT_QUEUE";
    public static final String DEAD_LETTER_TEST_ROUTING_KEY="DLT_TEST_KEY";
    public static final String DEAD_LETTER_REDIRECT_QUEUE="DLT_REDIRECT_QUEUE";
    public static final String DEAD_LETTER_REDIRECT_ROUTING_KEY="DLT_REDIRECT_KEY";

    /**
     * 声明死信交换机
     * 死信交换机对于交换机类型没有特殊要求,不一定要directExchange,可以为其他类型的
     */
    @Bean("deadLetterExchange")
    public Exchange deadLetterExchange(){
        return ExchangeBuilder.directExchange(DEAD_LETTER_EXCHANGE).durable(true).build();
    }

    /**
     * 声明死信队列
     */
    @Bean("deadLetterQueue")
    public Queue deadLetterQueue(){
        Map<String,Object> args = new HashMap<>();
        //x-dead-letter-exchange 声明死信交换机
        args.put("x-dead-letter-exchange",DEAD_LETTER_EXCHANGE);
        //x-dead-letter-routing-key 声明死信队列抛出异常重定向队列的routingkey(DLT_REDIRECT_KEY)
        args.put("x-dead-letter-routing-key",DEAD_LETTER_REDIRECT_ROUTING_KEY);
        return QueueBuilder.durable(DEAD_LETTER_QUEUE).withArguments(args).build();
    }

    /**
     * 声明重定向队列
     */
    @Bean("redirectQueue")
    public Queue redirectQueue(){
        return QueueBuilder.durable(DEAD_LETTER_REDIRECT_QUEUE).build();
    }

    /**
     * 死信队列绑定到死信交换机上
     */
    @Bean
    public Binding deadLetterQueueBinding(){
        return new Binding(
                DEAD_LETTER_QUEUE,
                Binding.DestinationType.QUEUE,
                DEAD_LETTER_EXCHANGE,
                DEAD_LETTER_TEST_ROUTING_KEY,
                null);
    }

    /**
     * 重定向队列通过RoutinKey绑定到死信队列上
     */
    @Bean
    public Binding deadLetterRedirectQueueBinding(){
        return new Binding(
                DEAD_LETTER_REDIRECT_QUEUE,
                Binding.DestinationType.QUEUE,
                DEAD_LETTER_EXCHANGE,
                DEAD_LETTER_REDIRECT_ROUTING_KEY,
                null);
    }

}

生产者
RabbitMQController

@GetMapping("/testDeadLetter")
@ResponseBody
public String testDeadLetter(@RequestParam String msg){
    /**
     * 发送消息
     * 参数1:交换机名称
     * 参数2:路由key
     * 参数3:发送的消息
     */
    rabbitTemplate.convertAndSend(RabbitDeadLetterConfig.DEAD_LETTER_EXCHANGE,
            RabbitDeadLetterConfig.DEAD_LETTER_TEST_ROUTING_KEY,msg);
    return "成功向死信交换机发送消息!";
}


死信队列消费者
/**
 * 死信队列消费者
 * 这里会抛出异常
 * @param msg:消息
 */
@RabbitListener(queues= RabbitDeadLetterConfig.DEAD_LETTER_QUEUE)
public void deadLetterConsumer(String msg){
    System.out.println("======正在尝试消费死信队列消息====");
    int i=1/0;//自行弄出异常
    System.out.println("消费者了消费:"+msg);
}

/**
 * 重定向队列消费者
 */
@RabbitListener(queues = RabbitDeadLetterConfig.DEAD_LETTER_REDIRECT_QUEUE)
public void deadLetterRedirectConsumer(String msg){
    System.out.println("重定向消费者消费了消息:"+msg);
}

测试

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

在这里插入图片描述

三、延迟队列

消息的TTL+死信Exchange结合=延迟队列
1、消息的TTL——消息的存货时间(通过设置消息的expiration字段或者x-message-ttl属性)。rabbitMQ可以设置队列的TTL和消息的TTL,队列TTL指的是该队列所有消息的存活时间,消息的TTL指的是单条消息的,所以一条消息在不同队列可以有不同的TTL,以小的为准。
2、Dead Letter Exchanges死信交换机
(1)一个消息被Consumer拒收了,并且reject方法的参数里是requeue是false。也就是说不会被再次放在队列里,被其他消费者使用
(2)上面的消息TTL到了,消息过期了
(3)队列的长度限制满了,排在前面的消息会被丢弃或者扔到死信路由上
在这里插入图片描述
代码
application.yml

spring:
# rabbitMQ配置
  rabbitmq:
    host: 39.97.123.123
    port: 5672
    virtual-host: my_vhost  #虚拟主机(相当于mysql的数据库库名)
    username: admin
    password: admin

    # 死信队列必要配置
    listener:
      simple:
        retry:
          enabled: true   #允许消息消费失败重试
          max-attempts: 3 #消息消费最多允许3次
          initial-interval: 1000  #消息多次消费间隔1s
        default-requeue-rejected: false #设置为false,会丢弃消息或者重新发布到死信队列

RabbitDelayLetterConfig

package com.jinv.studentinfo.config;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @Author: jinv
 * @CreateTime: 2020-06-14 00:51
 * @Description: 延迟队列配置
 */
@Configuration
public class RabbitDelayLetterConfig {
    /**
     * 延时交换机——交换机用于重新分配队列(接收死信队列中的过期消息,将其转发到需要延迟消息的模块队列)
     */
    @Bean("delayExchange")
    public DirectExchange exchange(){
        return new DirectExchange("X-DELAY-EXCHANGE");
    }

    /**
     * 实际消费队列
     * 用于延时消费的队列
     */
    @Bean("repeatTradeQueue")
    public Queue repeatTradeQueue(){
        return new Queue("X-RECIEVE-QUEUE",true,false,false,null);
    }

    /**
     * 绑定交换机兵指定routingkey(死信队列绑定延迟交换机和实际消费队列绑定延迟交换机的routingkey一直)
     */
    @Bean
    public Binding repeatTradeBinding(@Qualifier("repeatTradeQueue") Queue queue,
                                      @Qualifier("delayExchange") DirectExchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with("delay");
    }

    /**
     * 死信队列
     */
    @Bean
    public Queue delayLetterQueue(){
        Map<String,Object> args = new HashMap<>();
        //设置延迟时间
        args.put("x-message-ttl",1000*60);
        //设置绑定延时交换机(这里的绑定和上面的binding是有区别的,这里的绑定在15672客户端是看不到的)
        args.put("x-dead-letter-exchange","X-DELAY-EXCHANGE");
        //设置队列消息的routingkey
        args.put("x-dead-letter-routing-key","delay");
        return new Queue("X-DELAY-QUEUE",true,false,false,args);
    }



}

生产者
RabbitController

@GetMapping("/testDelayLetter")
@ResponseBody
public String testDealyLetter(@RequestParam String msg){
    //这里是给延迟队列发送消息,不需要事先配置routingkey,
    //消息进入延迟队列会自动获取队列赋予的routingkey
    rabbitTemplate.convertAndSend("X-DELAY-QUEUE","我要发送延迟消息");
    System.out.println("发送时间:"+LocalDateTime.now());
    return "已经发送延迟消息";
}

消费者
Mylistener

/**
 * 延迟队列消费者
 */
@RabbitListener(queues = "X-RECIEVE-QUEUE")
public void delayLetterConsumer(String msg){
    System.out.println("实际接收信息时间:"+LocalDateTime.now());
    System.out.println("消费者接收到的信息:"+msg);
}

测试结果(延迟一分钟)
在这里插入图片描述

四、消息确认机制
确认并且保证消息被送达:发布确认和事务支持(两者不可同时使用)在channel为事务时,不可引入确认模式,同样channel为确认模式下,不支持事务
1、发布确认
(1)消息发送成功确认
(2)消息发送失败回调
2、事务支持

五、消息追踪

有待补充高级应用和集群部署

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值