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

相关推荐
无责任此方_修行中4 分钟前
一个 GitHub Issue 标题如何让 4000 台电脑沦陷?
后端·npm·ai编程
SimonKing4 分钟前
开源免费!传统项目也可以接入天爱验证码(TAC),坑我来填
java·后端·程序员
猹叉叉(学习版)16 分钟前
【ASP.NET CORE】 13. DDD初步实现
笔记·后端·架构·c#·asp.net·.netcore
huabiangaozhi16 分钟前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
野犬寒鸦24 分钟前
从零起步学习计算机操作系统:进程篇(知识扩展提升)
java·服务器·开发语言·后端·面试
轩情吖33 分钟前
MySQL内置函数
android·数据库·c++·后端·mysql·开发·函数
IT_陈寒38 分钟前
JavaScript开发者必知的5个高效调试技巧,比console.log强10倍!
前端·人工智能·后端
小箌39 分钟前
springboot_02
java·spring boot·后端
超级大福宝41 分钟前
集群中服务器的个数为什么最好是奇数个
服务器·分布式·后端
吾诺1 小时前
springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice
spring boot·后端·docker