Bootstrap

京东一面:什么是消息轨迹?

  • 什么是消息轨迹

  • 消息轨迹配置

  • 消息轨迹的实现原理

  • 消息轨迹Topic支持方式

  • 用户自定义的TraceTopic实践

1. 什么是消息轨迹

RocketMQ的消息轨迹是一种用于追踪消息生产、存储、消费全链路状态的功能。它记录了消息从生产者发送到 Broker,再到消费者消费的完整生命周期信息,帮助开发者在分布式系统中快速定位消息问题(如消息丢失、重复消费、延迟等),并监控消息流转状态。

消息轨迹数据关键属性

Producer端Consumer端Broker端
生产实例信息消费实例信息消息的Topic
发送消息时间投递时间,投递轮次消息存储位置
消息是否发送成功消息是否消费成功消息的Key值
发送耗时消费耗时消息的Tag值

消息轨迹的核心作用

  • 问题排查:快速定位消息是否成功发送、存储、消费,以及失败原因。

  • 链路追踪:查看消息在生产者、Broker、消费者之间的流转路径和时间。

  • 状态监控:统计消息的发送/消费延迟、成功率等关键指标。

  • 数据审计:记录消息的完整生命周期,满足合规性要求。

2. 消息轨迹配置

如果RocketMQ 开启消息轨迹,增加这个配置:

traceTopicEnable=true

给大家贴出Broker端开启消息轨迹特性的properties配置文件内容(来源官网):

brokerClusterName=DefaultCluster
brokerName=broker-a
brokerId=0
deleteWhen=04
fileReservedTime=48
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH
storePathRootDir=/data/rocketmq/rootdir-a-m
storePathCommitLog=/data/rocketmq/commitlog-a-m
autoCreateSubscriptionGroup=true
## if msg tracing is open,the flag will be true
traceTopicEnable=true
listenPort=10911
brokerIP1=XX.XX.XX.XX1
namesrvAddr=XX.XX.XX.XX:9876

RocketMQ的消息轨迹功能支持普通模式和物理IO隔离模式

普通模式

  • 消息轨迹数据与普通业务消息共享Broker节点,集群中的每个Broker节点均可存储消息轨迹数据

  • 部署简单,无需额外配置。可能存在IO竞争问题,可能影响高吞吐量场景的性能。

  • 在Broker的配置文件中开启消息轨迹功能(traceTopicEnable=true),即可。

物理IO隔离模式

  • 消息轨迹数据与业务消息的存储完全隔离,需指定专用Broker节点单独存储轨迹数据

  • 避免IO资源竞争,提升整体吞吐量和稳定性,适合消息轨迹数据量大或对性能要求高的场景

  • RocketMQ集群中至少有两个Broker节点,其中一个Broker节点定义为存储消息轨迹数据的服务端

3. 消息轨迹的实现原理

RocketMQ 的消息轨迹功能通过以下方式实现:

  • 内置轨迹Topic:RocketMQ 会创建一个内部 Topic(默认名为 RMQ_SYS_TRACE_TOPIC),专门用于存储消息轨迹数据。

  • 钩子机制:生产者和消费者在发送/消费消息时,通过 Hook(钩子)拦截消息事件,生成轨迹数据并发送到轨迹 Topic。

  • 轨迹存储与查询:轨迹数据由 Broker 存储,用户可以通过 RocketMQ 控制台或 API 查询消息的完整轨迹。

流程简要总结就是:

  • 生产者:业务消息发送 → 钩子记录轨迹 → 内存队列缓冲 → 异步上报轨迹。

  • 消费者:消息消费 → 钩子记录轨迹 → 内存队列缓冲 → 异步上报轨迹。

  • 最终轨迹数据统一存储到 RMQ_SYS_TRACE_TOPIC,通过控制台查询。

在这里插入图片描述

4. 消息轨迹Topic支持方式

有些伙伴可能有疑问,上图中,Broker 的 RMQ_SYS_TRACE_TOPIC是什么呀?其实,RocketMQ的消息轨迹特性支持两种存储轨迹数据的方式:

  • 默认内置轨迹 Topic

  • 自定义轨迹 Topic

4.1 默认内置轨迹 Topic

  • Topic的名称为 RMQ_SYS_TRACE_TOPIC,它是RocketMQ 自动创建,无需用户手动配置。

  • 默认开启,只要生产者或消费者启用了消息轨迹(setEnableMsgTrace(true)),轨迹数据会自动发送到此 Topic。

  • Broker 自动管理该 Topic 的队列和存储。

  • 适用快速验证、测试环境或无需自定义轨迹管理的场景。

4.2 自定义轨迹 Topic

  • 用户可指定一个自定义的Topic名称(如MyApp_TraceTopic),用于存储轨迹数据。

  • 适用对轨迹数据有特殊存储或安全要求(如独立集群、分片策略)。

5. 用户自定义的TraceTopic代码实践

5.1 发送消息时开启消息轨迹

生产者代码示例(自定义轨迹Topic)

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

public class CustomTraceProducer {
    public static void main(String[] args) throws Exception {
        // 1. 创建生产者实例,并开启消息轨迹,指定自定义轨迹Topic
        // 参数说明:生产者组名, enableMsgTrace=true, 自定义轨迹Topic名称
        DefaultMQProducer producer = new DefaultMQProducer("OrderProducerGroup", true, "MyApp_TraceTopic");
        
        // 2. 设置NameServer地址(根据实际环境修改)
        producer.setNamesrvAddr("localhost:9876");
        producer.start();

        try {
            // 3. 构建订单消息(模拟业务场景)
            Message msg = new Message(
                "OrderTopic",                     // 业务Topic
                "PayOrder",                      // Tag(用于消息过滤)
                "Order_202307280001",            // 业务唯一Key(Message Key)
                "订单支付成功".getBytes(RemotingHelper.DEFAULT_CHARSET) // 消息体
            );

            // 4. 发送消息
            SendResult sendResult = producer.send(msg);
            System.out.println("消息发送结果: " + sendResult);
        } finally {
            // 5. 关闭生产者
            producer.shutdown();
        }
    }
}

5.2 消费者代码示例(自定义轨迹Topic)

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;

public class CustomTraceConsumer {
    public static void main(String[] args) throws Exception {
        // 1. 创建消费者实例,并开启消息轨迹,指定自定义轨迹Topic
        // 参数说明:消费者组名, enableMsgTrace=true, 自定义轨迹Topic名称
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("OrderConsumerGroup", true, "MyApp_TraceTopic");
        
        // 2. 设置NameServer地址(根据实际环境修改)
        consumer.setNamesrvAddr("localhost:9876");
        
        // 3. 订阅业务Topic(只消费PayOrder标签的消息)
        consumer.subscribe("OrderTopic", "PayOrder");
        
        // 4. 设置从队列头部开始消费(首次启动时)
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        
        // 5. 注册消息监听器(处理业务逻辑)
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            System.out.println("收到订单消息: " + new String(msgs.get(0).getBody()));
            // 模拟消费成功(若失败返回RECONSUME_LATER)
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        consumer.start();
        System.out.println("消费者已启动,等待订单消息...");
    }
}

5.3 轨迹数据验证

  1. 确保自定义轨迹Topic存在:
  • 若 Broker 未开启自动创建 Topic(autoCreateTopicEnable=false),需手动创建:
sh mqadmin updateTopic -n localhost:9876 -t MyApp_TraceTopic -c DefaultCluster
  1. 发送测试消息:

运行生产者代码,发送一条订单消息到 OrderTopic,轨迹数据将写入 MyApp_TraceTopic。

  1. 查询消息轨迹:

使用 RocketMQ 控制台或命令行工具,输入消息的 MsgID 或 Message Key 查询轨迹:

sh mqadmin QueryMsgTraceById -n localhost:9876 -i "0A1234567890ABCDEF"  # 替换为实际MsgID
;