这里是weihubeats ,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党
背景
最近在查看消费进度的时候发现pop
消费的GID查看不到消费进度,所以想一探究竟。为啥push
、pull
消费方式可以查看到,pop
不行
RocketMQ版本
- 5.1.0
功能入口
在官方dashboard
Consumer页面我都可以查看消息的消费进度
一般分两种情况
一种是啥也没有,TPS显式为-1
另一种是有详细的进度。还能看到机器的消费ip、消费进度等
我们通过F12
进行简单的抓包看看具体是请求的哪个接口 consumer/queryTopicByConsumer.query
rocketmq-dashboard 源码
java
@Override
public List<TopicConsumerInfo> queryConsumeStatsList(final String topic, String groupName) {
ConsumeStats consumeStats = null;
try {
consumeStats = mqAdminExt.examineConsumeStats(groupName, topic);
}
catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
List<MessageQueue> mqList = Lists.newArrayList(Iterables.filter(consumeStats.getOffsetTable().keySet(), new Predicate<MessageQueue>() {
@Override
public boolean apply(MessageQueue o) {
return StringUtils.isBlank(topic) || o.getTopic().equals(topic);
}
}));
Collections.sort(mqList);
List<TopicConsumerInfo> topicConsumerInfoList = Lists.newArrayList();
TopicConsumerInfo nowTopicConsumerInfo = null;
Map<MessageQueue, String> messageQueueClientMap = getClientConnection(groupName);
for (MessageQueue mq : mqList) {
if (nowTopicConsumerInfo == null || (!StringUtils.equals(mq.getTopic(), nowTopicConsumerInfo.getTopic()))) {
nowTopicConsumerInfo = new TopicConsumerInfo(mq.getTopic());
topicConsumerInfoList.add(nowTopicConsumerInfo);
}
QueueStatInfo queueStatInfo = QueueStatInfo.fromOffsetTableEntry(mq, consumeStats.getOffsetTable().get(mq));
queueStatInfo.setClientInfo(messageQueueClientMap.get(mq));
nowTopicConsumerInfo.appendQueueStatInfo(queueStatInfo);
}
return topicConsumerInfoList;
}
这段代码主要是通过去broker
拿取数据,然后做一些数据组装
核心就是
ini
consumeStats = mqAdminExt.examineConsumeStats(groupName, topic);
这里注意topic这个参数传的是null
这里我们看看DefaultMQAdminExtImpl
的实现
这一快的代码还挺长。我们挑重点分析
分析前我们思考一个问题。我们在dashboard上面并不知道broker
的地址。
所以要请求broker
去获取consumer
的消费信息我们需要如何获取到集群的broker
地址呢?
答案是通过重试topic
获取
也就是源码开始的那几行代码
java
TopicRouteData topicRouteData = null;
List<String> routeTopics = new ArrayList<>();
routeTopics.add(MixAll.getRetryTopic(consumerGroup));
if (topic != null) {
routeTopics.add(topic);
routeTopics.add(KeyBuilder.buildPopRetryTopic(topic, consumerGroup));
}
for (int i = 0; i < routeTopics.size(); i++) {
try {
topicRouteData = this.examineTopicRouteInfo(routeTopics.get(i));
if (topicRouteData != null) {
break;
}
} catch (Throwable e) {
if (i == routeTopics.size() - 1) {
throw e;
}
}
}
重试队列push
、pull
的生成重试topic
的规则是
%RETRY%
+ GID
,比如消费者是GID_XIAO_ZOU
,那么重试队列就是%RETRY%GID_XIAO_ZOU
拿到的TopicRouteData
元数据中就有broker
ip地址
注意这里的
RocketMQ
dashboard
在查询pop
消费进度的时候有一个bugpop生成充实topic的规则是
"%RETRY%" + cid + "_" + topic
也就是如果刚才的这个topic是pop消费,订阅的
topic
是ORDER
,那么重试队列的名称是%RETRY%GID_XIAO_ZOU_ORDER
那么此时就会因为找不到TopicRouteData
查询消费进度失败。最简单的修复方式就是手动创建一个重试topic
我们继续上面的源码分析。 在我们拿到topicRouteData
就会去拿到集群中所有master
的broker
地址,如果没有master
节点就从slave
节点随机拿一个
拿到broker
信息后就去所有broker
获取消费信息。
自此client
端的源码就分析完了。我们来看看client
端的请求码是多少
arduino
public static final int GET_CONSUME_STATS = 208;
broker端源码
broker这边的源码也比较少。我们来简单看看
- 获取到
consumer
订阅的topic
java
topics = this.brokerController.getConsumerOffsetManager().whichTopicByConsumer(requestHeader.getConsumerGroup());
- 找到
topic
对应的queue信息
java
TopicQueueMappingDetail mappingDetail = this.brokerController.getTopicQueueMappingManager().getTopicQueueMapping(topic);
- 获取每个
queue
的最大消费位点、消费位点、消息拉取位点、后消费时间
返回给client
的消费位点是已提交消费位点和消息拉取的位点取最大值
java
offsetWrapper.setPullOffset(Math.max(consumerOffset, pullOffset));
总结
总得来说官方dashboard
对于pop的消息查询存在bug。
因为获取broker
的地址信息是通过查询重试topic
的路由信息获取到的,如果没有重试topic
就查询不到broker
消费进度。
因为pop的重试队列规则修改了。旧版本的dashboard
没有兼容所有会查询不到