事件

同事在生产环境部署了RocketMQ 4.5,同时开启了自动创建Topic的功能。今天通过rocketmq-console-ng管理后台查看某个主题时发现,明明是两个主,但是topic怎么只在一个broker(broker-a)上创建呢?(看下面的图)

 

rocketmq java 创建topic rocketmq集群创建topic_消息发送

rocketmq java 创建topic rocketmq集群创建topic_发送消息_02

出于对技术的认真,通过看源码和百度,看看RocketMQ在autoCreateTopicEnable模式下是怎么创建Topic。

大体有以下几个步骤

1、broker启动时创建以默认的配置信息创建默认topic;

 2、broker将本地的topic信息发送给nameserver(默认是30s发送一次),nameserver更新本地topic信息(此时默认topic包含两个broker信息)

 3、消息发送者向NameServer查询路由信息,在没有创建时返回空信息,mq会使用默认的topic再次查找,因为autoCreateTopicEnable=true, NameServer返回默认主题的路由信息

 4、消息发送者通过默认主题的路由信息轮询选择一个队列发送(包含要创建的Topic信息)

 5、broker收到消息后,先会从TopicConfigManager中查询topic路由信息,不存在的情况下但存在默认路由配置,那就会根据创建topic及路由信息(注意,这里创建的队列数是从 消息发送者上传过来的)

 6、新的topic创建完后,上报给NameServer,从而再同步给消息发送者(默认是30s同步一次)

 7、消息发送者再有这个topic的消息时,就直接根据路由信息获取队列发送了。

好像还是没有回答问题 !!

其实问题已经显现了:

    因为路由信息在broker上生成,当发送者发送消息的个数小于某个阀值时(留个悬念),RocketMQ根据轮询规则,消息会落在同一个broker上,该broker上生成路由规则上报给NameServer后,再同步给发送者,这样在发送者的内存中就只有一个broker的队列信息了,NameServer也就只有一个broker的路由信息。

    

下面我们通过源码再了解一下

1、路由信息是如何生成的?

       在rocketmq源码中,我们发现(下图),在broker启动时,会实例一个TopicConfigManager对象,在其构造方法中对于autoCreateTopicEnable=true时,会在topicConfigTable中添加默认主题路由信息,路由信息会随着broker向nameserver发心跳包一起发送给到nameserver,nameserver更新本地路由信息。

      在默认topic中,大家发现吗,在启动时代码还指定了读写队列数(默认=8),所以当我们是2个主broker时,就会有16个队列了。


topicConfig.setReadQueueNums(this.brokerController.getBrokerConfig() .getDefaultTopicQueueNums()); topicConfig.setWriteQueueNums(this.brokerController.getBrokerConfig() .getDefaultTopicQueueNums());


rocketmq java 创建topic rocketmq集群创建topic_发送消息_03

 

2、消息发送者 获取默认topic并发送信息:mq会先查询当前消息topick路由信息,没有再查询默认topic路由信息。

rocketmq java 创建topic rocketmq集群创建topic_发送消息_04

3、当获取到默认路由信息时,按轮询取一个队列(注意:这里对默认队列的个数进行了改变,代码中的值=4)

rocketmq java 创建topic rocketmq集群创建topic_消息发送_05

4、发送者发送消息,同时设置topic的队列数为default值=4

rocketmq java 创建topic rocketmq集群创建topic_心跳包_06

 

5、broker接入消息后,没有topic的情况下,根据信息生成topic信息,因为发送者上送的队列数是4,所以创建的队列也就是4了。创建完路由信息后,信息将发送给NameServer,从而消息发送者也将获取该topic的路由信息,并以新的路由信息进行消息的投递。

rocketmq java 创建topic rocketmq集群创建topic_心跳包_07