RocketMQ源码分析之消费进度查询(附带pop消费进度查询坑处理)

这里是weihubeats ,觉得文章不错可以关注公众号小奏技术,文章首发。拒绝营销号,拒绝标题党

背景

最近在查看消费进度的时候发现pop消费的GID查看不到消费进度,所以想一探究竟。为啥pushpull消费方式可以查看到,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;
                }
            }
        }

重试队列pushpull的生成重试topic的规则是

%RETRY% + GID,比如消费者是GID_XIAO_ZOU,那么重试队列就是%RETRY%GID_XIAO_ZOU

拿到的TopicRouteData元数据中就有brokerip地址

注意这里的RocketMQ dashboard在查询pop消费进度的时候有一个bug

pop生成充实topic的规则是"%RETRY%" + cid + "_" + topic

也就是如果刚才的这个topic是pop消费,订阅的topicORDER,那么重试队列的名称是%RETRY%GID_XIAO_ZOU_ORDER
那么此时就会因为找不到TopicRouteData查询消费进度失败。最简单的修复方式就是手动创建一个重试topic

我们继续上面的源码分析。 在我们拿到topicRouteData就会去拿到集群中所有masterbroker地址,如果没有master节点就从slave节点随机拿一个

拿到broker信息后就去所有broker获取消费信息。

自此client端的源码就分析完了。我们来看看client端的请求码是多少

arduino 复制代码
public static final int GET_CONSUME_STATS = 208;

broker端源码

broker这边的源码也比较少。我们来简单看看

  1. 获取到consumer订阅的topic
java 复制代码
topics = this.brokerController.getConsumerOffsetManager().whichTopicByConsumer(requestHeader.getConsumerGroup());
  1. 找到topic对应的queue信息
java 复制代码
TopicQueueMappingDetail mappingDetail = this.brokerController.getTopicQueueMappingManager().getTopicQueueMapping(topic);
  1. 获取每个queue的最大消费位点、消费位点、消息拉取位点、后消费时间

返回给client的消费位点是已提交消费位点和消息拉取的位点取最大值

java 复制代码
offsetWrapper.setPullOffset(Math.max(consumerOffset, pullOffset));

总结

总得来说官方dashboard对于pop的消息查询存在bug。

因为获取broker的地址信息是通过查询重试topic的路由信息获取到的,如果没有重试topic就查询不到broker消费进度。

因为pop的重试队列规则修改了。旧版本的dashboard没有兼容所有会查询不到

相关推荐
awljwlj30 分钟前
黑马点评复习—缓存相关【包含可能的问题和基础知识复习】
java·后端·spring·缓存
XY_墨莲伊35 分钟前
【实战项目】基于B/S结构Flask+Folium技术的出租车轨迹可视化分析系统(文末含完整源代码)
开发语言·后端·python·算法·机器学习·flask
神奇小汤圆38 分钟前
为什么Claude Code这么强?我从泄漏的源码里挖到了核心秘密
后端
精品源码屋1 小时前
千万级CSV/Excel表统计教程:基于本地数据库的自然语言单表、多表分析 | DT-Bot工作流
后端
Gopher_HBo1 小时前
CompletableFuture运用原理
java·后端
Leinwin1 小时前
GPT-6 API接入完全指南:Symphony架构下的多模态调用与最佳实践
后端·python·flask
snakeshe10101 小时前
Java Web 应用部署实战:从单机到分布式的三种方式
后端
lolo大魔王1 小时前
Go语言的函数与指针的定义
开发语言·后端·golang
神奇小汤圆2 小时前
从两套系统到一条 SQL:SelectDB search() 搞定日志的搜索与分析
后端