[toc]
| 单词 | 词性 | 音标 | 含义 |
|---|---|---|---|
| ttl | n. | /tiː tiː el/ | 生存时间(消息过期时间) |
| dead letter | n. | /ded ˈletə(r)/ | 死信(无法被消费的消息) |
| dlx | n. | /diː el eks/ | 死信交换机(死信转入的交换机) |
| expire | v. | /ɪkˈspaɪə(r)/ | 过期(消息超时未被消费) |
| delay | v./n. | /dɪˈleɪ/ | 延迟(推迟一段时间) |
| retry | v./n. | /ˈriːtraɪ/ | 重试(失败后再次尝试) |
Lecture06-RabbitMQ-延迟队列(TTL+死信)
1、需求场景
电商系统:用户下单后,30 分钟检查该订单是否已支付,未支付则自动取消(或发送提醒)。
如果不用延迟队列,常规做法是"定时任务轮询订单表",又笨又费资源,关键是不准确:你检测到它过期时,已经过期很久了。
延迟队列的思路是:把"检查订单支付"这个动作本身延迟 30 分钟再执行——消息到点(30 分钟后)才被真正的业务消费者收到。
2、原理:延迟消息 + 死信队列
核心是两条队列 + 一个死信交换机:
- 设一个延迟队列:给它设置消息 TTL(生存时间)= 30 分钟,并绑定死信交换机 DLX
- 生产者把"检查订单"这条消息发到延迟队列
- 延迟队列 没有消费者去消费它(它就是用来"存"消息、让消息过期的)
- 30 分钟后消息到期 → 被自动转投到死信交换机 DLX
- 死信交换机按路由键把消息路由到业务队列
- 业务消费者监听业务队列 → 到点(30 分钟后)才收到消息,执行"检查订单是否已支付"
[生产者] --发消息--> [延迟队列 TTL=30min] --(30min后到期)--> [死信交换机 DLX] --路由--> [业务队列] --投递--> [业务消费者: 检查订单支付]
一句话:延迟队列不消费,只让消息"躺到过期",过期后借死信交换机转给真正的业务队列。业务消费者 30 分钟后才拿到消息。
3、创建所需设备
①所需设备清单
- 正常交换机:atguigu.delay.normal.exchange
- 正常交换机绑定正常队列的路由键:atguigu.delay.normal.routing.key
- 正常队列:atguigu.delay.normal.queue
- 死信交换机:atguigu.delay.dead.exchange
- 死信交换机绑定死信队列的路由键:atguigu.delay.dead.routing.key
- 死信队列:atguigu.delay.dead.queue
②特殊设定
正常队列需要在消息超时后把消息转到死信队列,所以需要增加额外设置:




4、Java 代码
①生产者端
把消息发送给正常队列:
@Test
public void test02() {
String exchangeName = "atguigu.delay.normal.exchange";
String routingKey = "atguigu.delay.normal.routing.key";
String message = "This message will be dead.";
rabbitTemplate.convertAndSend(exchangeName, routingKey, message);
}
②消费者端
监听死信队列:
@RabbitListener(queues = {"atguigu.delay.dead.queue"})
public void receiveDeadMessage(String deadMessage, Message message, Channel channel) throws IOException {
log.info("死信消息内容:" + deadMessage);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
5、验证
- 教学时把 TTL 改短(如 10 秒),发一条消息:
- 立即看 延迟队列:有 1 条 ready 消息(没有消费者消费它)
- 此时业务队列是空的、消费者没收到
- 10 秒后:延迟队列里消息消失,业务队列出现该消息,消费者收到 → 说明延迟生效 ✅
- 也可以在 Management UI 里直接看两个队列的 ready 数变化。
6、要点 / 常见问题
- 为什么延迟队列没有消费者? 因为它只负责"存"消息让消息到期;真正的业务在死信后的业务队列上消费。
- TTL 设在哪? 设的是队列级 TTL(x-message-ttl),即该队列里每条消息最多存活 30 分钟,到期转死信。
- 这个方案在 RabbitMQ 4 还成立吗? 成立。TTL + 死信机制在 RabbitMQ 4 依然有效(经典队列和 Quorum 队列都支持)。
- 用插件行不行?
rabbitmq_delayed_message_exchange插件在 3 里可以正常使用;但是 4 里官方已标记"不再维护",不推荐新项目依赖。
7、本节验证
- 理解延迟队列(TTL+死信)的原理(延迟队列不消费,到期转死信交换机)✅
- 会用 Spring Boot 声明延迟队列/死信交换机/业务队列三件套 ✅
- 会验证延迟生效(把 TTL 改短观察)✅
- 分清"延迟队列(定时调度)"与"Quorum 延迟重试(失败退避)"✅