RocketMQ 5.x 的定时消息新特性(基于时间轮的精准定时)
RocketMQ 5.x 引入了精准定时消息,突破了 18 个等级的限制,支持任意时间点的定时投递:
// 5.x 新特性:精准定时消息
Message msg = new Message(“order_topic”, “内容”.getBytes());
// 指定精确的投递时间戳(毫秒)
msg.setDeliverTimeMs(System.currentTimeMillis() + 30 * 60 * 1000); // 30 分钟后
producer.send(msg);
底层实现变化:
4.x 5.x
18 个固定等级 支持任意时间点
每个等级一个 Queue 基于 Timing Wheel(时间轮) 算法
定时线程扫描 时间轮 + 多级时间轮,高效调度
适合固定延迟场景 适合任意定时场景
时间轮定时消息
槽位到期
消息投递时间
任意时间戳
插入时间轮槽位
时间轮每秒推进
触发投递
高效调度 O(1) 复杂度
支持海量定时消息
时间轮的优势:
可以处理任意时间点的定时消息,不再受 18 个等级限制
时间轮算法在调度大量定时任务时性能远优于传统的扫描方式
支持取消定时消息(通过消息 ID)
延迟消息的使用限制与最佳实践
使用限制:
限制 说明
❌ 不支持事务消息 延迟消息不能和事务消息组合使用
❌ 不支持批量消息 批量消息不能设置延迟等级
❌ 4.x 只支持 18 个等级 不能自定义延迟时间(5.x 解决了)
❌ 消息投递后不可取消 一旦 Broker 调度投递,无法撤回(5.x 支持取消部分)
最佳实践:
评估延迟粒度:如果只需要秒/分钟级别的延迟,4.x 的 18 个等级通常够用
5.x 新项目推荐使用定时消息:更灵活,支持取消
避免过长的延迟(> 2 小时):长时间延迟消息占用 Broker 存储,建议采用外部调度方案
监控延迟消息堆积:延迟消息在 SCHEDULE_TOPIC_XXXX 中堆积,需要监控其数量,避免积压过多导致 Broker 内存压力
十一、消息轨迹与消息查询
消息轨迹的作用与配置开启
消息轨迹(Message Trace) 记录了消息从生产到消费的完整链路,是问题排查的利器。
核心作用:
消息轨迹能回答的问题
❓ 这条消息是谁发的?
❓ 什么时候发的?
❓ 发到了哪个 Broker?
❓ 被消费了吗?
❓ 谁消费的?
❓ 消费成功还是失败?
配置开启:
Broker 端配置(broker.conf):
开启消息轨迹
traceTopicEnable=true
轨迹数据存储的 Topic 名称(默认)
msgTraceTopicName=RMQ_SYS_TRACE_TOPIC
Producer 端开启:
DefaultMQProducer producer = new DefaultMQProducer(“producer_group”);
producer.setEnableMsgTrace(true); // 开启轨迹
producer.setMsgTraceTopic(“RMQ_SYS_TRACE_TOPIC”);
Consumer 端开启:
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(“consumer_group”);
consumer.setEnableMsgTrace(true);
consumer.setMsgTraceTopic(“RMQ_SYS_TRACE_TOPIC”);
消息轨迹的数据采集与存储(traceTopic)
消息轨迹通过 Hook 机制 无侵入地采集数据:
RMQ_SYS_TRACE_TOPIC
Broker
Trace Hook
Producer
RMQ_SYS_TRACE_TOPIC
Broker
Trace Hook
Producer
- 发送消息前触发 before
- 记录发送开始时间、IP 等
- 发送消息
- 返回响应
- 发送后触发 after
- 记录耗时、结果
- 将轨迹数据作为普通消息
异步发送到 traceTopic
轨迹数据内容:
字段 说明
traceId 全局唯一追踪 ID
messageId 消息 ID
key 业务 Key
topic Topic 名称
producerGroup 生产者组
consumerGroup 消费者组
sendTime 发送时间
consumeTime 消费时间
sendCost 发送耗时
consumeCost 消费耗时
clientIp 客户端 IP
status 状态(成功/失败)
errorMsg 错误信息
