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

这里是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元数据中就有brokerip地址

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

pop生成充实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这边的源码也比较少。我们来简单看看

  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没有兼容所有会查询不到

相关推荐
mldong10 分钟前
同一个节点接力办几轮,流程才往下走:jeeflow 的后加签
后端·架构
量化分析码农13 分钟前
【Python量化多因子实战 03】多因子怎么合成?等权、IC 加权与回归加权实测
后端
深蓝AI9 小时前
JWT 不是登录方案:三种登录态架构怎么选
后端
starzy19909 小时前
深入理解Scala Map:从实现原理到工程实践
开发语言·后端·scala
卷无止境10 小时前
凌晨三点的绿灯
后端
excel11 小时前
基于 GPT 的自动发布文章接口方案:从一句话或一张图片生成并发布内容
前端·javascript·后端
风若飞12 小时前
Spring Ai 入门遇到问题1
java·后端·spring
AI入职记13 小时前
Spring AI 结构化输出:结构 100% 通过,严格准确率只有 57%
后端·ai编程
aZhe的全栈知识分享13 小时前
AI 还原 Figma 效果总达不到预期?先别急着让它写代码
前端·后端·面试
码事漫谈13 小时前
WorkBuddy 一直更新卡死?两个毛病,一套处理办法
后端