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

相关推荐
郑祎亦23 分钟前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
本当迷ya36 分钟前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
paopaokaka_luck2 小时前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
捂月3 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
瓜牛_gn3 小时前
依赖注入注解
java·后端·spring
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
喜欢猪猪4 小时前
Django:从入门到精通
后端·python·django
一个小坑货4 小时前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet274 小时前
【Rust练习】22.HashMap
开发语言·后端·rust