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

相关推荐
碳苯29 分钟前
【rCore OS 开源操作系统】Rust 枚举与模式匹配
开发语言·人工智能·后端·rust·操作系统·os
kylinxjd1 小时前
spring boot发送邮件
java·spring boot·后端·发送email邮件
2401_857439694 小时前
Spring Boot新闻推荐系统:用户体验优化
spring boot·后端·ux
进击的女IT5 小时前
SpringBoot上传图片实现本地存储以及实现直接上传阿里云OSS
java·spring boot·后端
一 乐6 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
艾伦~耶格尔9 小时前
Spring Boot 三层架构开发模式入门
java·spring boot·后端·架构·三层架构
man20179 小时前
基于spring boot的篮球论坛系统
java·spring boot·后端
攸攸太上10 小时前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
罗曼蒂克在消亡10 小时前
graphql--快速了解graphql特点
后端·graphql
潘多编程10 小时前
Spring Boot与GraphQL:现代化API设计
spring boot·后端·graphql