RocketMQ源码分析:透彻理解Topic的创建更新内部实现原理

884 阅读4分钟

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

源码版本

  • rocketmq:release-5.1.0

背景

继上一章我们分析了client端Nameserver地址更新的源码实现方式 现在我们继续研究client是如何创建更新topic并与brokernameserver交互的

探索

这里我们源码探索的入口并不打算先从rocketmq源码包开始,因为创建topic的入口更多的是在rocketmq-dashboard,所以我们从rocketmq-dashboard,rocketmq-dashboard的版本使用最新的master,反正rocketmq-dashboard也没怎么维护了,所以倒是无所谓

入口

我们直接全局搜索topicCreate

会发现很容易找到这个controller:TopicController

然后入口也很明显就是topicCreateOrUpdateRequest这个方法

我们进入到topicService中的createOrUpdate方法看看

比较核心的两行代码我们可以注意一下

ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();

这里需要获取的是所有masterbroker,因为只有masterbroker才是可写的 实际上不通过上面的方式获取,我们还可以通过如下代码获取

Set<String> masterSet = CommandUtil.fetchMasterAddrByClusterName(mqAdmin, mqCluster.getName());

毕竟有提供直接的工具类帮我们获取,我们为什么不用呢

这里是通过集群mqAdminExt去获取集群信息,实际是通过netty远程从nameserver获取的,我们可以简单看看这块通信代码

public static final int GET_BROKER_CLUSTER_INFO = 106;

我们通过code去找到server的业务处理器

获取broker集群的代码也很简单

这里仅仅是拿到所有masterbroker地址,还没有正真开始创建topic

创建topic的核心方法是

mqAdminExt.createAndUpdateTopicConfig

需要注意的是这里的创建方式是for循环去所有主master broker创建

所以我们指定一个topic多少个readQueueNumswriteQueueNums就会在所有broker上建立相同数量的queue

所以像网上有些图比如:

这种在正常没有broker扩容的情况下是不对的,因为所有的broker上面的queue应该是相同数量的

客户端我们这里分析完了,接下来我们还是要去broker上面的源码去寻找我们需要真相。

要找到broker相关的请求处理器也很简单,我们看看createTopic发送的RequestCode是多少,就可以了

可以看到是

RequestCode.UPDATE_AND_CREATE_TOPIC

顺带提一句的是实际rocketmq-dashboard中使用的这些方法其实也是依赖了rocketmq中的一些模块的sdk比如

  • rocketmq-clinet
  • rocketmq-tools

broker

我们通过寻找RequestCode的使用

就能找到broker的处理逻辑

  • AdminBrokerProcessorupdateAndCreateTopic(ChannelHandlerContext ctx, RemotingCommand request)

这段代码还是挺长的,我们挑重点分析

  1. 方法添加了synchronized,防止并发冲突
final CreateTopicRequestHeader requestHeader =
            (CreateTopicRequestHeader) request.decodeCommandCustomHeader(CreateTopicRequestHeader.class);

方法decodeCommandCustomHeader就是将客户端的请求参数转换到 CreateTopicRequestHeader对象中具体的转换,实际在编解码的时候所有属性都已经写入到extFields属性了,我们可以简单看看

3. validateTopic去校验topic的合法性 这里的合法性校验很简单,我们看看代码就知道了

  1. 校验是否为更新系统的topic
      if (brokerController.getBrokerConfig().isValidateSystemTopicWhenUpdateTopic()) {
            if (TopicValidator.isSystemTopic(topic)) {
                response.setCode(ResponseCode.SYSTEM_ERROR);
                response.setRemark("The topic[" + topic + "] is conflict with system topic.");
                return response;
            }
        }
  1. CreateTopicRequestHeader requestHeader转换为TopicConfig

  1. 更新topic信息写入到broker
this.brokerController.getTopicConfigManager().updateTopicConfig(topicConfig);

topic相关的元数据信息存储默认在TopicConfigManager配置

可以看到默认是在user.home

这里我们也可以简单看看实际的元数据存储是什么样子的

  1. 推送brokertopic相关信息到nameserver
this.brokerController.registerIncrementBrokerData(topicConfig, this.brokerController.getTopicConfigManager().getDataVersion());

这里我们直接进入到最里面的通信模块,看几个核心的点,就是broker通过获取了nameServerAddressList然后循环去更新topic信息

总结

至此我们就分析完了topic创建、更新流程,我们总结一下

  1. client循环向集群中的所有masterbroker注册topic信息
  2. broker接受到创建或更新topic信息后本地创建topic然后写入本地文件中,同时会更新broker的内存topic信息,然后向所有nameserver更新topic信息

可以看到整体逻辑还是很清晰的

本文正在参加「金石计划」