RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列

RabbitMQ相关–TTL过期时间、DLX死信队列、延迟队列

一、TTL(Time-To-Live 过期时间)

  • 指定一条消息的过期时间
  • 指定一个队列的过期时间,队列中所有消息都有同样的过期时间
  • 如果通知指定了消息、队列过期时间,则优先较小的

1、应用场景

  • 订单超时取消
  • 确认短信或邮件超时失效

2、指定消息过期时间

2.1 创建交换机和队列
//指定交换机名称
public static final String TTL_DIRECT_EXCHANGE = "ttlDirectExchange";
//指定队列名称
public static final String TTL_DIRECT_QUEUE = "ttlDirectExchange";
//指定路由key
public static final String TTL_DIRECT_ROUTING_KEY = "ttlDirectRoutingKey";

//定义一个TTL交换机和队列并绑定
@Bean
public DirectExchange ttlDirectExchange(){
    return new DirectExchange(TTL_DIRECT_EXCHANGE);
}
@Bean
public Queue ttlQueue(){
return new Queue(TTL_DIRECT_QUEUE,true,false,false);
}
@Bean
public Binding ttlBinding(){
    return BindingBuilder.bind(ttlQueue()).to(ttlDirectExchange()).with(TTL_DIRECT_ROUTING_KEY);
}
2.2 生产者创建消息
/**
 * 发送ttl消息
 */

    @Override
    public void sentTtlMessage(String message) {
        MessageProperties messageProperties = new MessageProperties();
        //第一种方法 单位是毫秒,设置过期时间
//        Message msg = MessageBuilder
//                .withBody(message.getBytes())
//                .setExpiration("30000")
//                .build();
        //第二种方法
        messageProperties.setExpiration("30000");
        Message msg = new Message(message.getBytes(),messageProperties);
        rabbitTemplate.convertAndSend(RabbitMQConfig.TTL_DIRECT_EXCHANGE,RabbitMQConfig.TTL_DIRECT_ROUTING_KEY,msg);
    }

2.3 管理页面可以查看消失时间

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第1张图片

3、指定队列过期时间

3.1 队列参数

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第2张图片

参数介绍:
1、name: 队列的名称;
2、actualName: 队列的真实名称,默认用name参数,如果name为空,则根据规则生成一个;
3、durable: 是否持久化;
4、exclusive: 是否独享、排外的;
5、autoDelete: 是否自动删除;
6、arguments:队列的其他属性参数,有如下可选项,可参看图2的arguments:
(1)x-message-ttl:消息的过期时间,单位:毫秒;
(2)x-expires:队列过期时间,队列在多长时间未被访问将被删除,单位:毫秒;
(3)x-max-length:队列最大长度,超过该最大值,则将从队列头部开始删除消息;
(4)x-max-length-bytes:队列消息内容占用最大空间,受限于内存大小,超过该阈值则从队列头部开始删除消息;
(5)x-overflow:设置队列溢出行为。这决定了当达到队列的最大长度时消息会发生什么。有效值是drop-head、reject-publish或reject-publish-dlx。仲裁队列类型仅支持drop-head;
(6)x-dead-letter-exchange:死信交换器名称,过期或被删除(因队列长度超长或因空间超出阈值)的消息可指定发送到该交换器中;
(7)x-dead-letter-routing-key:死信消息路由键,在消息发送到死信交换器时会使用该路由键,如果不设置,则使用消息的原来的路由键值
(8)x-single-active-consumer:表示队列是否是单一活动消费者,true时,注册的消费组内只有一个消费者消费消息,其他被忽略,false时消息循环分发给所有消费者(默认false)
(9)x-max-priority:队列要支持的最大优先级数;如果未设置,队列将不支持消息优先级;
(10)x-queue-mode(Lazy mode):将队列设置为延迟模式,在磁盘上保留尽可能多的消息,以减少RAM的使用;如果未设置,队列将保留内存缓存以尽可能快地传递消息;
(11)x-queue-master-locator:在集群模式下设置镜像队列的主节点信息。 

Queue

public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, @Nullable Map<String, Object> arguments) {
    super(arguments);
    Assert.notNull(name, "'name' cannot be null");
    this.name = name;
    this.actualName = StringUtils.hasText(name) ? name : Base64UrlNamingStrategy.DEFAULT.generateName() + "_awaiting_declaration";
    this.durable = durable;
    this.exclusive = exclusive;
    this.autoDelete = autoDelete;
}
3.2 代码实现
@Bean
public Queue ttlQueue(){
    Map<String,Object> arguments = new HashMap<>();
    //单位毫秒
    arguments.put("x-message-ttl",5000);
    return new Queue(TTL_DIRECT_QUEUE,true,false,false,arguments);
}

二、DLX死信队列

死信队列DLX:Dead Letter Exchange(死信交换机),当消息成为dead message后,可以重新发送至另一交换机,这个交换机就叫做死信交换机

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第3张图片

1.成为死信消息的条件

  • 消息被消费者basic.reject或者basic.nack方法并且requeue参数设置为flase的方式进行消息确定
  • 消息由于消息有效期(TTL)过期
  • 消息由于队列超过其长度限制而被丢弃,创建队列时可以通过x-max-length设置长度

2.代码实现

/**
 * 测试死信队列
 */

//指定交换机名称
public static final String DLX_DIRECT_EXCHANGE = "dlxDirectExchange";
//指定队列名称
public static final String DLX_DIRECT_QUEUE = "dlxDirectExchange";
//指定路由key
public static final String DLX_DIRECT_ROUTING_KEY = "dlxDirectRoutingKey";

//定义一个DLX交换机和队列并绑定
@Bean
public DirectExchange dlxDirectExchange(){
    return new DirectExchange(DLX_DIRECT_EXCHANGE);
}
@Bean
public Queue dlxQueue(){
    return new Queue(DLX_DIRECT_QUEUE);
}
@Bean
public Binding dlxBinding(){
    return BindingBuilder.bind(dlxQueue()).to(dlxDirectExchange()).with(DLX_DIRECT_ROUTING_KEY);
}

/**
 * 测试TTL
 */

//指定交换机名称
public static final String TTL_DIRECT_EXCHANGE = "ttlDirectExchange";
//指定队列名称
public static final String TTL_DIRECT_QUEUE = "ttlDirectExchange";
//指定路由key
public static final String TTL_DIRECT_ROUTING_KEY = "ttlDirectRoutingKey";

//定义一个TTL交换机和队列并绑定
@Bean
public DirectExchange ttlDirectExchange(){
    return new DirectExchange(TTL_DIRECT_EXCHANGE);
}
@Bean
public Queue ttlQueue(){
    Map<String,Object> arguments = new HashMap<>();
    arguments.put("x-message-ttl",5000);
    arguments.put("x-dead-letter-exchange",DLX_DIRECT_EXCHANGE);
    arguments.put("x-dead-letter-routing-key",DLX_DIRECT_ROUTING_KEY);
    return new Queue(TTL_DIRECT_QUEUE,true,false,false,arguments);
}
@Bean
public Binding ttlBinding(){
    return BindingBuilder.bind(ttlQueue()).to(ttlDirectExchange()).with(TTL_DIRECT_ROUTING_KEY);
}

3.现象

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第4张图片

三、延迟队列

1.应用场景

  • 订单在三十分钟内未支付则自动取消
  • 用户注册验证码有效期十分钟
  • 消息提醒

2.实现方式

2.1 TTL+死信队列(比较麻烦)

生产者生产一条延迟消息,根据延迟时间不同,通过不同的routingkey路由到不同的延迟队列,每个队列都设置了相应的TTL属性,并绑定死信交换机,根据routingKey不同,路由到不同的死信队列,消费者监听队列即可。

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第5张图片

2.2 插件方式实现
  1. 访问地址:https://www.rabbitmq.com/community-plugins.html ,下载rabbitmq_delayed_message_exchange插件,然后解压到RabbitMQ的插件目录。
  2. 进入RabbitMQ安装目录下的sbin目录,执行命令使插件生效,然后重启RabbitMQ

    rabbitmq-plugins enable rabbitmq_delayed_message_exchange
    3.容器挂载
docker run -d --rm --name rabbitmq \
-v /qqquser/rabbitmq/:/root/data \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=admin \
-p 5672:5672 -p 15672:15672 \
rabbitmq3-management

命令说明:

-d:后台方试运行
-v:主机和容器的目录映射关系,":"前为主机目录,之后为容器目录
-e:指定账号密码
-p:端口映射,映射主机端口 -> 容器的端口
--rm:容器退出时就能够自动清理容器内部的文件系统

4.把插件上传服务器

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第6张图片
5.进入容器查看是否挂载成功,并且把插件移动到/plugins,启动插件

cp /root/data/rabbitmq_delayed_message_exchange-3.9.0.ez /plugins 
cd /sbin
rabbitmq-plugins enable rabbitmq_delayed_message_exchange

6.docker restart 重启容器

3.代码实现

/**
 * 测试延迟队列
 */

//指定交换机名称
public static final String DELAYED_DIRECT_EXCHANGE = "delayedDirectExchange";
//指定队列名称
public static final String DELAYED_DIRECT_QUEUE = "delayedDirectExchange";
//指定路由key
public static final String DELAYED_DIRECT_ROUTING_KEY = "delayedDirectRoutingKey";

//定义一个延迟交换机和队列并绑定
@Bean
public CustomExchange delayedDirectExchange(){
    Map<String,Object> args = new HashMap<>();
    args.put("x-delayed-type","direct");
    return new CustomExchange(DELAYED_DIRECT_EXCHANGE,"x-delayed-message",true,false,args);
}
@Bean
public Queue delayedQueue(){
    return new Queue(DELAYED_DIRECT_QUEUE,true,false,false);
}
@Bean
public Binding delayedBinding(){
    return BindingBuilder.bind(delayedQueue()).to(delayedDirectExchange()).with(DELAYED_DIRECT_ROUTING_KEY).noargs();
}

生产者

/**
 * 发送延迟消息
 */
public void sendDelayedMessage(String message,Integer delayedTime);

消费者

@Override
@RabbitListener(queues = {RabbitMQConfig.DELAYED_DIRECT_QUEUE})
public void receiveMessage3(String message) {
    System.out.println("接收的延迟消息:"+message + new Date().toString());
}

发送消息

public class ProducerApplication {

    public static void main(String[] args) {
        ApplicationContext ac=SpringApplication.run(ProducerApplication.class,args);
        RabbitMqService rabbitMqService= (RabbitMqService) ac.getBean("rabbitmqService");
        rabbitMqService.sendDelayedMessage("发送延迟消息",5000);;
        rabbitMqService.sendDelayedMessage("发送延迟消息10秒",10000);;
        rabbitMqService.sendDelayedMessage("发送延迟消息20秒",20000);;

    }
}

效果

RabbitMQ相关--TTL过期时间、DLX死信队列、延迟队列_第7张图片

你可能感兴趣的:(rabbitmq,java,分布式)