一、核心原理概述
RocketMQ的延迟消息实现采用 "预置延迟等级 + 定时扫描转发" 的机制,并非真正的实时延迟,就是通过预定延迟等级将消息暂存到特定队列,等待时间到达后再投递给消费者。
1. 实现方式
RocketMQ 将延时消息转换为普通消息,通过 SCHEDULE_TOPIC_XXXX 主题进行分级存储和消费。

2. 延迟级别
RocketMQ 一共支持18个等级的延迟投递,具体时间如下:
| 1 | 1s | 10 | 6min |
| 2 | 5s | 11 | 7min |
| 3 | 10s | 12 | 8min |
| 4 | 30s | 13 | 9min |
| 5 | 1min | 14 | 10min |
| 6 | 2min | 15 | 20min |
| 7 | 3min | 16 | 30min |
| 8 | 4min | 17 | 1h |
| 9 | 5min | 18 | 2h |
// RocketMQ预定义的18个延迟等级
private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";
// 对应18个SCHEDULE_TOPIC_XXXX队列
3. 整体流程

二、核心实现步骤

发送阶段
java
// 生产者发送延迟消息
Message msg = new Message("TestTopic", "Hello RocketMQ".getBytes());
// 设置延迟级别(对应上面级别的索引,从1开始)
msg.setDelayTimeLevel(3); // 延迟10秒
producer.send(msg);
内部转换流程
消息标记:Broker 收到延迟消息后,将原 Topic 和 QueueId 存入消息属性
主题切换:将消息的实际 Topic 改为 SCHEDULE_TOPIC_XXXX
队列分配:根据延迟级别分配到对应的延迟队列
-
延迟级别1 → SCHEDULE_TOPIC_XXXX 的 Queue 0
-
延迟级别2 → SCHEDULE_TOPIC_XXXX 的 Queue 1
-
…
-
每个延迟级别对应一个专门的队列
定时扫描机制

java
// 简化后的处理逻辑
class ScheduleMessageService {
// 定时任务,每秒执行一次 (实际会根据延迟级别进行分级延迟扫描)
public void start() {
for (int level = 1; level <= maxDelayLevel; level++) {
// 计算当前级别对应的延迟时间
long delayTime = computeDeliverTimestamp(level);
// 扫描对应队列中到期的消息
scanAndDeliver(level, delayTime);
}
}
}
消息投递
扫描到期消息:每个延迟队列有独立的定时任务,按时间轮询扫描
恢复原主题:从消息属性中取出原始 Topic 和 QueueId
重新投递:将消息存入原始 Topic 的 CommitLog
消费者消费:消费者从原始 Topic 正常消费消息
三、 存储结构

四、Broker核心处理流程

五、 限制与改进
配置延迟级别
properties
# broker.conf
messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
重要限制
固定延迟级别:不支持任意时间延迟,只能使用预设级别
时间精度:秒级精度
最大延迟:默认最长2小时(可配置)
消息顺序:延迟消息会破坏严格的消息顺序
5.0+ 版本改进
RocketMQ 5.0 引入了 TimerWheel(时间轮) 优化:
-
支持任意时间延迟(毫秒级精度)
-
更高的性能,O(1) 时间复杂度
-
支持更长的延迟时间(数天级别)
最佳实践
java
// 最佳实践
public class DelayMessageExample {
public void sendDelayMessage() {
Message msg = new Message("OrderTopic", "订单超时取消".getBytes());
// 根据业务需求选择合适的延迟级别
// 订单超时:30分钟 → level 16
// 支付提醒:15分钟 → 可选择10m或20m级别
msg.setDelayTimeLevel(16); // 30分钟
// 消息去重:延迟消息可能需要配合唯一Key
msg.setKeys("ORDER_123456");
producer.send(msg);
}
}
总结
RocketMQ 延迟消息通过 "主题转换 + 分级延迟队列 + 定时扫描" 实现,虽然不支持任意时间点延迟,但满足了大多数业务场景(如订单超时、定时提醒等)。对于更灵活的延迟需求,可考虑升级到 5.0+ 版本或使用时间轮实现。


