当前位置: 首页 > news >正文

RabbitMQ高级特性--TTL和死信队列

目录

1.TTL

1.1设置消息的TTL

1.1.1配置交换机&队列

1.1.2发送消息

 1.1.3运行程序观察结果

1.2设置队列的TTL 

1.2.1配置队列和交换机的绑定关系

1.2.2发送消息

1.2.3运行程序观察结果

1.3两者区别

2.死信队列

2.1 声名队列和交换机

2.2正常队列绑定死信交换机

2.3制造死信产生的条件

2.4 发送消息

2.5测试死信 

 2.6常见面试题

2.6.1死信队列的概念

2.6.2死信的来源

2.6.3死信队列的应⽤场景


1.TTL

TTL(Time to Live, 过期时间), 即过期时间. RabbitMQ可以对消息和队列设置TTL.
当消息到达存活时间之后, 还没有被消费,就会被自动清除。

1.1设置消息的TTL

目前有两种方法可以设置消息的TTL

一是设置队列的TTL,队列中所有消息都有相同的过期时间,二是对消息本身进行单独设置,每条消息的TTL可以不同,如果两种方法一起使用,则消息的TTL以两者之间较小的那个数值决定。

先看针对每条消息设置TTL

针对每条消息设置TTL的方法是在发送消息的方法中加入expiration的属性参数,单位为ms

1.1.1配置交换机&队列

//TTL
public static final String TTL_QUEUE = "ttl_queue";
public static final String TTL_EXCHANGE_NAME = "ttl_exchange";

//ttl
//1. 交换机
@Bean("ttlExchange")
public Exchange ttlExchange() {
 return
ExchangeBuilder.fanoutExchange(Constant.TTL_EXCHANGE_NAME).durable(true).build(
);
}
//2. 队列
@Bean("ttlQueue")
public Queue ttlQueue() {
 return QueueBuilder.durable(Constant.TTL_QUEUE).build();
}
//3. 队列和交换机绑定 Binding
@Bean("ttlBinding")
public Binding ttlBinding(@Qualifier("ttlExchange") FanoutExchange exchange, 
@Qualifier("ttlQueue") Queue queue) {
 return BindingBuilder.bind(queue).to(exchange);
}

1.1.2发送消息

@RequestMapping("/ttl")
public String ttl(){
 String ttlTime = "10000";//10s
 rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE_NAME, "", "ttl 
test...", messagePostProcessor -> {
 messagePostProcessor.getMessageProperties().setExpiration(ttlTime);
 return messagePostProcessor;
 });
 return "发送成功!";
}

 1.1.3运行程序观察结果

发送消息后可以看到Ready数为1

十秒后,刷新页面发现消息已消失

1.2设置队列的TTL 

设置队列的TTL的方法是在创建队列时,加入x-message-ttl参数实现的,单位是ms

1.2.1配置队列和交换机的绑定关系

public static final String TTL_QUEUE2 = "ttl_queue2";
//设置ttl
@Bean("ttlQueue2")
public Queue ttlQueue2() {
 //设置20秒过期
 return QueueBuilder.durable(Constant.TTL_QUEUE2).ttl(20*1000).build();
}
//3. 队列和交换机绑定 Binding
@Bean("ttlBinding2")
public Binding ttlBinding2(@Qualifier("ttlExchange") FanoutExchange exchange, 
@Qualifier("ttlQueue2") Queue queue) {
 return BindingBuilder.bind(queue).to(exchange);
}

设置过期时间,也可以采用以下方式:

@Bean("ttlQueue2")
public Queue ttlQueue2() {
 Map<String, Object> arguments = new HashMap<>();
 arguments.put("x-message-ttl",20000);//20秒过期
 return
QueueBuilder.durable(Constant.TTL_QUEUE2).withArguments(arguments).build();
}

1.2.2发送消息

@RequestMapping("/ttl")
 public String ttl() {
// String ttlTime = "30000";//10s
// //发送带ttl的消息
// rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE_NAME, "", "ttl test...", //messagePostProcessor -> {
// messagePostProcessor.getMessageProperties().setExpiration(ttlTime);
// return messagePostProcessor;
// });
 //发送不带ttl的消息
 rabbitTemplate.convertAndSend(Constant.TTL_EXCHANGE_NAME, "", "ttl 
test...");
 return "发送成功!";
 }

1.2.3运行程序观察结果

 运行后发现,新增了一个队列,队列Features有一个TTL标识

 发送消息后,可以看到Ready消息为1

采⽤发布订阅模式, 所有与该交换机绑定的队列都会收到消息

20s后,刷新页面,发现消息已经删除

 

 由于ttl_queue队列, 未设置过期时间, 所以ttl_queue的消息未删除。

1.3两者区别

设置队列TTL属性的方法, ⼀旦消息过期, 就会从队列中删除
设置消息TTL的方法, 即使消息过期, 也不会马上从队列中删除, 而是在即将投递到消费者之前进⾏判定的
为什么这两种方法的处理方法不一致?
因为设置队列过期时间, 队列中已过期的消息肯定在队列头部, RabbitMQ只要定期从队头开始扫描是否有过期的消息即可.
而设置消息TTL的方式, 每条消息的过期时间不同, 如果要删除所有过期消息需要扫描整个队列, 所以不如等到此消息即将被消费时再判定是否过期, 如果过期再进行删除即可.

2.死信队列

死信(dead message)简单理解就是因为种种原因无法被消费的信息,就是死信

有死信,自然就有死信队列。当消息在一个队列中变成死信之后,它能被重新发送到另一个交换机中,这个交换机就是DLX(Dead Letter Exchange),绑定DLX的队列,就称为死信队列(Dead Letter Queue)简称DLQ

消息变成死信主要有以下几个原因:

1.消息被拒绝(Basic.Reject/Basic.Nack),并且设置requeue参数为false 

2.消息过期

3.队列达到最大长度

2.1 声名队列和交换机

//死信队列
public static final String DLX_EXCHANGE_NAME = "dlx_exchange";
public static final String DLX_QUEUE = "dlx_queue";
public static final String NORMAL_EXCHANGE_NAME = "normal_exchange";
public static final String NORMAL_QUEUE = “narmal_queue”;
/**
 * 死信队列相关配置
 */
@Configuration
public class DLXConfig {
 //死信交换机
 @Bean("dlxExchange")
 public Exchange dlxExchange(){
 return
ExchangeBuilder.topicExchange(Constant.DLX_EXCHANGE_NAME).durable(true).build()
;
 }
 //2. 死信队列
 @Bean("dlxQueue")
 public Queue dlxQueue() {
 return QueueBuilder.durable(Constant.DLX_QUEUE).build();
 }
 //3. 死信队列和交换机绑定 Binding
 @Bean("dlxBinding")
 public Binding dlxBinding(@Qualifier("dlxExchange") Exchange exchange, 
@Qualifier("dlxQueue") Queue queue) {
 return BindingBuilder.bind(queue).to(exchange).with("dlx").noargs();
 }
 //正常交换机
 @Bean("normalExchange")
 public Exchange normalExchange(){
 return
ExchangeBuilder.topicExchange(Constant.NORMAL_EXCHANGE_NAME).durable(true).buil
d();
 }
 //正常队列
 @Bean("normalQueue")
 public Queue normalQueue() {
 return QueueBuilder.durable(Constant.NORMAL_QUEUE).build();
 }
 //正常队列和交换机绑定 Binding
 @Bean("normalBinding")
 public Binding normalBinding(@Qualifier("normalExchange") Exchange 
exchange, @Qualifier("normalQueue") Queue queue) {
 return BindingBuilder.bind(queue).to(exchange).with("normal").noargs();
 }
}

2.2正常队列绑定死信交换机

当这个队列中存在死信时,RabbitMQ会自动的把这个消息重新发布到设置的DLX上,进而被路由到另一个队列,即死信队列,可以监听这个死信队列中的消息以进行相应的处理

@Bean("normalQueue")
public Queue normalQueue() {
 Map<String, Object> arguments = new HashMap<>();
 arguments.put("x-dead-letter-exchange",Constant.DLX_EXCHANGE_NAME);//绑定死信队列
 arguments.put("x-dead-letter-routing-key","dlx");//设置发送给死信队列的
RoutingKey
 return QueueBuilder.durable(Constant.NORMAL_QUEUE).withArguments(arguments).build();
}

简写为

return QueueBuilder.durable(Constant.NORMAL_QUEUE)
 .deadLetterExchange(Constant.DLX_EXCHANGE_NAME)
 .deadLetterRoutingKey("dlx").build();

2.3制造死信产生的条件

@Bean("normalQueue")
public Queue normalQueue() {
 Map<String, Object> arguments = new HashMap<>();
 arguments.put("x-dead-letter-exchange",Constant.DLX_EXCHANGE_NAME);//绑定死
信队列
 arguments.put("x-dead-letter-routing-key","dlx");//设置发送给死信队列的
RoutingKey
 //制造死信产⽣的条件
 arguments.put("x-message-ttl",10000);//10秒过期
 arguments.put("x-max-length",10);//队列⻓度
 return
QueueBuilder.durable(Constant.NORMAL_QUEUE).withArguments(arguments).build();
}

简写为:

return QueueBuilder.durable(Constant.NORMAL_QUEUE)
 .deadLetterExchange(Constant.DLX_EXCHANGE_NAME)
 .deadLetterRoutingKey("dlx")
 .ttl(10*1000)
 .maxLength(10L)
 .build();

2.4 发送消息


 @RequestMapping("/dlx")
 public void dlx() {
 //测试过期时间, 当时间达到TTL, 消息⾃动进⼊到死信队列
 rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE_NAME, "normal", 
"dlx test...");
 //测试队列⻓度
// for (int i = 0; i < 20; i++) {
// rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE_NAME, "normal", "dlx test...");
// }
// //测试消息拒收
// rabbitTemplate.convertAndSend(Constant.NORMAL_EXCHANGE_NAME, "normal", "dlx test...");
 }

2.5测试死信 

 程序启动后观察队列:

队列Features说明:
D: durable的缩写, 设置持久化
TTL: Time to Live, 队列设置了TTL
Lim: 队列设置了⻓度(x-max-length)
DLX: 队列设置了死信交换机(x-dead-letter-exchange)
DLK: 队列设置了死信RoutingKey(x-dead-letter-routing-key)
测试过期时间,到达过期时间后,进入死信队列:
发送之后:

 10s后:

⽣产者⾸先发送⼀条消息,然后经过交换器(normal_exchange)顺利地存储到队列(normal_queue)中.由于队列normal_queue设置了过期时间为10s, 在这10s内没有消费者消费这条消息, 那么判定这条消息过期. 由于设置了DLX, 过期之时, 消息会被丢给交换器(dlx_exchange)中, 这时根据RoutingKey匹配, 找到匹配的队列(dlx_queue), 最后消息被存储在queue.dlx这个死信队列里。

 2.6常见面试题

死信队列作为RabbitMQ的高级特性,也是面试的一大重点

2.6.1死信队列的概念

死信(Dead Letter)是消息队列中的⼀种特殊消息, 它指的是那些⽆法被正常消费或处理的消息. 在消息队列系统中, 如RabbitMQ, 死信队列用于存储这些死信消息

2.6.2死信的来源

1) 消息过期: 消息在队列中存活的时间超过了设定的TTL
2) 消息被拒绝: 消费者在处理消息时, 可能因为消息内容错误, 处理逻辑异常等原因拒绝处理该消息. 如果拒绝时指定不重新⼊队(requeue=false), 消息也会成为死信.
3) 队列满了: 当队列达到最大长度, 无法再容纳新的消息时, 新来的消息会被处理为死信.

2.6.3死信队列的应⽤场景

对于RabbitMQ来说, 死信队列是⼀个⾮常有⽤的特性. 它可以处理异常情况下,消息不能够被消费者正确消费而被置⼊死信队列中的情况, 应⽤程序可以通过消费这个死信队列中的内容来分析当时所遇到的
异常情况, 进而可以改善和优化系统.
⽐如: 用户支付订单之后, ⽀付系统会给订单系统返回当前订单的⽀付状态
为了保证⽀付信息不丢失, 需要使⽤到死信队列机制. 当消息消费异常时, 将消息投⼊到死信队列中, 由订单系统的其他消费者来监听这个队列, 并对数据进行处理(比如发送⼯单等,进行人工确认).
场景的应⽤场景还有:
消息重试:将死信消息重新发送到原队列或另⼀个队列进行重试处理.
消息丢弃:直接丢弃这些⽆法处理的消息,以避免它们占⽤系统资源.
⽇志收集:将死信消息作为⽇志收集起来,⽤于后续分析和问题定位

相关文章:

  • socket演示程序3(udp)
  • 《符号之纱与血肉之躯:具身智能范式的哲学重构与AI发展新图景》
  • 透过TCP/IP看HTTP
  • 深度学习篇---模型GPU训练
  • 监控平台——SkyWalking部署
  • Spring AOP中为所有类型通知传递参数的完整示例,包含详细注释和参数传递方式
  • 【数据结构】哈夫曼树
  • 74. Linux设备树详解
  • 基于springboot课程学习与互动平台(源码+lw+部署文档+讲解),源码可白嫖!
  • SQL注入点判断数据库类型
  • 从“制造”到“智造”:生产线自动检测的技术变革与实践
  • 【力扣hot100题】(017)矩阵置零
  • 火山引擎智能数据洞察 ChatBI 适配 DeepSeek-R1 及 DeepSeek-V3
  • 【商城实战(75)】数据分析指标体系搭建:从0到1的技术指南
  • 基于Halcon仿VM流程列表的执行效果
  • 深入解析MapReduce工作流程:从核心原理到实战优化
  • 第五十二章 Spring之再进一步——Boot
  • 深度神经网络全解析:原理、结构与方法对比
  • MySQL-复制表的两种常见方式
  • AI日报 - 2025年03月28日
  • 日本女做受网站BB/西安网站制作推广
  • 网站建设学习学校/营销推广方案包括哪些内容
  • 经典广告推广词/seo培训学什么
  • 六安网站建设/杭州seo优化公司
  • 网站开发工程师 北大青鸟/网销怎么找客户资源
  • 全屏网站模板/在线培训系统