【面试题】RabbitMQ 怎么实现延迟队列?

RabbitMQ 实现延迟队列主要有以下几种方式:

1. TTL + 死信队列(最常用)

原理

  • 设置消息或队列的 TTL(Time-To-Live)
  • 消息过期后成为死信,转发到死信队列
  • 消费者从死信队列获取延迟消息

实现步骤

// 1. 创建死信交换机
channel.exchangeDeclare("dlx.exchange", "direct", true);

// 2. 创建死信队列
Map<String, Object> dlxArgs = new HashMap<>();
dlxArgs.put("x-dead-letter-exchange", "dlx.exchange");
dlxArgs.put("x-dead-letter-routing-key", "dlx.routingKey");

// 3. 创建延迟队列(设置TTL)
Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", 10000); // 10秒TTL
args.put("x-dead-letter-exchange", "dlx.exchange");
args.put("x-dead-letter-routing-key", "dlx.routingKey");
channel.queueDeclare("delay.queue", true, false, false, args);

// 4. 绑定
channel.queueBind("delay.queue", "normal.exchange", "normal.routingKey");
channel.queueBind("dlx.queue", "dlx.exchange", "dlx.routingKey");

2. rabbitmq-delayed-message-exchange 插件(推荐)

安装插件

# 下载插件(版本需匹配RabbitMQ版本)
rabbitmq-plugins enable rabbitmq_delayed_message_exchange

使用示例

// 1. 声明延迟交换机
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare(
    "delayed.exchange", 
    "x-delayed-message", 
    true, false, args
);

// 2. 发送延迟消息
Map<String, Object> headers = new HashMap<>();
headers.put("x-delay", 5000); // 延迟5秒

AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder();
props.headers(headers);

channel.basicPublish(
    "delayed.exchange", 
    "routing.key", 
    props.build(), 
    message.getBytes()
);

3. 消息级别 TTL

// 为单条消息设置TTL
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
    .expiration("10000") // 10秒后过期
    .build();

channel.basicPublish(
    "exchange", 
    "routingKey", 
    properties, 
    message.getBytes()
);

4. 定时轮询数据库方案

// 将延迟消息存入数据库
public void sendDelayedMessage(Message message, long delaySeconds) {
    // 计算执行时间
    Date executeTime = new Date(System.currentTimeMillis() + delaySeconds * 1000);
    // 存入数据库
    delayMessageRepository.save(message, executeTime);
    
    // 定时任务轮询
    @Scheduled(fixedDelay = 5000)
    public void processDelayedMessages() {
        List<Message> readyMessages = delayMessageRepository
            .findReadyMessages(new Date());
        for (Message msg : readyMessages) {
            // 发送到RabbitMQ
            rabbitTemplate.convertAndSend(msg);
        }
    }
}

对比总结

方案 优点 缺点 适用场景
TTL+死信队列 无需插件,RabbitMQ原生支持 1. 队列只能设置固定延迟时间
2. 消息级别TTL可能产生队头阻塞
固定延迟时间的场景
延迟交换机插件 1. 每条消息可单独设置延迟
2. 无队头阻塞问题
需要安装插件 灵活延迟、精确控制
数据库方案 1. 延迟时间可持久化
2. 支持复杂调度
1. 依赖外部存储
2. 时效性较差
高可靠性、长延迟场景

最佳实践建议

  1. 短延迟(秒/分钟级):使用延迟交换机插件
  2. 固定延迟:使用TTL+死信队列
  3. 长延迟(小时/天级):使用数据库+定时任务
  4. 高精度延迟:结合Redis有序集合
# Spring Boot 配置示例
spring:
  rabbitmq:
    host: localhost
    port: 5672
  # 延迟交换机插件支持
  rabbitmq:
    delayed:
      exchange:
        enabled: true

选择方案时需考虑:延迟精度、消息量、系统复杂度、是否需要持久化等因素。

posted @ 2025-12-30 09:39  佛祖让我来巡山  阅读(173)  评论(0)    收藏  举报

佛祖让我来巡山博客站 - 创建于 2018-08-15

开发工程师个人站,内容主要是网站开发方面的技术文章,大部分来自学习或工作,部分来源于网络,希望对大家有所帮助。

Bootstrap中文网