RabbitMQ中的过期时间、死信队列、延迟队列

一. TTL(Time To Live)

消息的过期时间有两种设置方式:

1. 通过队列属性设置消息过期时间

@Bean("ttlQueue") 
public Queue queue() {
    Map<String, Object> map = new HashMap<String, Object>(); 
    map.put("x-message-ttl", 10000); // 队列中的消息未被消费 10 秒后过期 
    return new Queue("TTL_QUEUE", true, false, false, map);
}

2. 设置单条消息的过期时间

MessageProperties messageProperties = new MessageProperties(); 
messageProperties.setExpiration("4000"); // 消息的过期属性,单位 ms
Message message = new Message("这条消息 4 秒后过期".getBytes(), messageProperties); 
rabbitTemplate.send("TTL_EXCHANGE", "test.ttl", message);

如果同时指定了Message TTL 和Queue TTL,则优先较小的那一个。

二. 死信队列

消息在某些情况下会变成死信(Dead Letter)。队列在创建的时候可以指定一个死信交换机DLX(Dead Letter Exchange)。死信交换机绑定的队列被称为死信队列DLQ(Dead Letter Queue),DLX实际上也是普通的交换机,DLQ也是普通的队列。

什么情况下消息会变成死信?

1.消息被消费者拒绝并且未设置重回队列

2.消息过期

3.队列达到最大长度,超过了 Max length(消息数)或者 Max length bytes(字节数),最先入队的消息会被发送到 DLX。

实现过程:

1.声明死信交换机 DEAD_LETTER_EXCHANGE 、死信队列 DEAD_LETTER_QUEUE,相互绑定。

@Bean("deadLetterExchange")
public TopicExchange deadLetterExchange() {
    return new TopicExchange("GP_DEAD_LETTER_EXCHANGE", true, false, new HashMap<>()); 
}
​
@Bean("deadLetterQueue")
public Queue deadLetterQueue() {
    return new Queue("DEAD_LETTER_QUEUE", true, false, false, new HashMap<>()); 
}

@Bean
public Binding bindingDead(@Qualifier("deadLetterQueue") Queue queue, @Qualifier("deadLetterExchange") TopicExchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with("#"); // 无条件路由 
}

2.声明交换机 SIMPLE_EXCHANGE、队列 SIMPLE_QUEUE,相互绑定。

3.指定队列的死信交换机 DEAD_LETTER_EXCHANGE。

4.队列中的消息10秒钟过期,因为没有消费者,会变成死信,通过死信交换机进入死信队列。

@Bean("simpleExchange")
public DirectExchange exchange() {
    return new DirectExchange("SIMPLE_EXCHANGE", true, false, new HashMap<>()); 
}

​@Bean("simpleQueue") 
public Queue queue() {
    Map<String, Object> map = new HashMap<>();
    // 10 秒钟后成为死信
    map.put("x-message-ttl", 10000); 
    // 队列中的消息变成死信后,进入死信交换机
    map.put("x-dead-letter-exchange", "DEAD_LETTER_EXCHANGE"); 
    return new Queue("SIMPLE_QUEUE", true, false, false, map); 
}
​
@Bean
public Binding binding(@Qualifier("simpleQueue") Queue queue,@Qualifier("simpleExchange") DirectExchange exchange) {
    return BindingBuilder.bind(queue).to(exchange).with("hujy.test"); 
}

三.延迟队列

RabbitMQ 本身不支持延迟队列,总的来说有三种实现方案:

1.先存储到数据库,用定时任务扫描。

2.利用 RabbitMQ的死信队列(Dead Letter Queue)实现。

主要过程:

生产者 —> 原交换机 —> 原队列(超过 TTL 之后) —> 死信交换机 —> 死信队列 —> 最终消费者

使用死信队列实现延时消息的缺点:

(1)如果统一用队列来设置消息的 TTL,当梯度非常多的情况下,比如 1 分钟,2 分钟,5 分钟,10 分钟,20 分钟,30 分钟......需要创建很多交换机和队列来路由消息。

(2)如果单独设置消息的 TTL,则可能会造成队列中的消息阻塞,即前一条消息没有出队(没有被消费),后面的消息无法投递。比如第一条消息过期 TTL 是 30min,第二条消息 TTL 是 10min。10 分钟后,即使第二条消息应该投递了,但是由于第一条消息 还未出队,所以无法投递。

(3)可能存在一定时间误差

3.利用 rabbitmq-delayed-message-exchange 插件实现。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@从入门到入土

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值