方法一:利用 TTL 和 DLX(死信队列)
RabbitMQ 本身不支持直接的延时队列,但可以通过 TTL(Time-To-Live)和 DLX(Dead Letter Exchange)组合实现延时效果。
- 创建普通队列并设置 TTL,绑定到业务交换机。
- 为队列配置死信交换机(DLX)和死信路由键。
- 消息过期后,自动转发到死信队列,由消费者处理。
示例代码:
// 声明死信交换机和队列
channel.exchangeDeclare("dlx.exchange", "direct");
channel.queueDeclare("dlx.queue", true, false, false, null);
channel.queueBind("dlx.queue", "dlx.exchange", "dlx.routing.key");
// 声明业务队列并设置 TTL 和 DLX
Map<String, Object> args = new HashMap<>();
args.put("x-message-ttl", 10000); // TTL 10秒
args.put("x-dead-letter-exchange", "dlx.exchange");
args.put("x-dead-letter-routing-key", "dlx.routing.key");
channel.queueDeclare("delay.queue", true, false, false, args);
方法二:使用 RabbitMQ 插件(rabbitmq_delayed_message_exchange)
RabbitMQ 3.5.8 及以上版本支持官方延时插件,需手动安装。
- 下载插件并启用:
rabbitmq-plugins enable rabbitmq_delayed_message_exchange - 声明自定义交换机类型为
x-delayed-message,并设置路由方式(如direct)。
示例代码:
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("delayed.exchange", "x-delayed-message", true, false, args);
channel.queueDeclare("delayed.queue", true, false, false, null);
channel.queueBind("delayed.queue", "delayed.exchange", "delayed.key");
// 发送延时消息
Map<String, Object> headers = new HashMap<>();
headers.put("x-delay", 5000); // 延时5秒
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder()
.headers(headers)
.build();
channel.basicPublish("delayed.exchange", "delayed.key", props, message.getBytes());
方法三:外部定时任务 + 消息存储
适用于高精度延时需求,但实现复杂度较高。
- 将延时消息存储到数据库(如 MySQL),记录目标发送时间。
- 通过定时任务(如 Spring Scheduler)扫描到期消息。
- 将消息投递到 RabbitMQ 普通队列。
示例代码片段:
@Scheduled(fixedDelay = 1000)
public void scanDelayedMessages() {
List<Message> messages = repository.findBySendTimeBefore(new Date());
messages.forEach(msg -> {
rabbitTemplate.convertAndSend("target.exchange", "target.key", msg);
repository.delete(msg);
});
}
注意事项
- TTL+DLX 缺点:队列中消息过期时间是固定的,若动态调整需为每条消息设置单独 TTL(可能影响性能)。
- 插件优点:支持动态延时,但需确保插件兼容性和集群配置一致性。
- 定时任务缺点:依赖外部存储,可能引入一致性问题(如任务失败需补偿)。
选择方法时需根据业务场景权衡实现复杂度和延时精度。
1万+

被折叠的 条评论
为什么被折叠?



