背景

RocketMQ 源码版本 4.9.1

下载了 RocketMQ 源码,在本地 IDE 中正常启动了 Broker 服务 和 NameServer 服务。

生产者发送消息的 demo 如下

在发送消息的过程中报错了,报错信息如下

从报错信息可以看到: **Topic 对应的路由信息没有正常获取到(Topic 名称为 TopicTest)。**也难怪,Broker 启动后没有人为地去创建 Topic 对应的队列,发送消息自然没办法获取到路由信息。

想到 Broker 有自动创建 Topic 的机制,可以通过在 Broker 的配置文件中添加如下配置:

autoCreateTopicEnable = true

问题在于即使配置了这个参数,重启 Broker 服务之后,发送消息时还是如上的报错,因此打算仔细看看 RocketMQ 自动创建 Topic 的实现原理。

自动创建Topic机制

首先需要解决两个问题

  • W1:Broker 注册路由信息方式
  • W2:生产者获取路由信息的策略

路由信息注册(Broker)

  • Broker 节点在启动时会先初始化当前 Broker 的路由信息,根据 autoCreateTopicEnable 参数的配置情况决定是否要添加【默认主题】的路由信息
  • Broker 节点会定期向 NameServer 注册路由信息

路由信息主要包含的内容

  • 当前 Broker 节点存在的 Topic 列表
  • 每个 Topic 对应的队列分配情况(读写队列数量)

1.Broker 节点启动时,会开启一个定时任务,定期向 NameServer 注册路由信息

2.调用具体的注册方法,topicConfigWrapper 对象中包含本次需要注册的路由信息

3.topicConfigWrapper 对象的构建过程,其实是把 topicConfigTable 对象包装了一层

4.topicConfigTable 对象类型为 ConcurrentMap,Map 的 Key 为 Topic 名称,Value 为 Topic 对应的路由信息(包含读写队列数量信息)

5.下面看到 topicConfigTable 对象的初始化过程,主要看到关于【自动创建 Topic】 的逻辑,其它代码先省略(初始化了一系列系统预设的 Topic 路由信息)

  • 判断 Broker 是否开启了自动创建 Topic 的开关,即开头讲的 autoCreateTopicEnable = true 的配置
  • 如果开启了自动创建 Topic,则会往 topicConfigTable 对象中放入一个【默认主题】的路由信息, 名称为 TBW102,这边将它称为【TBW102默认路由信息】
  • 因此最终往 NameServer 中注册的路由信息包含 【TBW102默认路由信息】

路由信息获取(生产者)

  • 生产者发送消息时,会根据当前消息指定的 Topic 查询路由信息,如果本地缓存没有查询到,则尝试从 NameServer 服务查询
  • 当没有查询到指定 Topic 的路由信息时,会使用系统【默认主题】的名称再次尝试查询路由,如果查询到【默认主题】的路由信息,则正常发送消息

1.发送消息前,先尝试获取消息对应 Topic 的路由信息

2.获取路由信息

3.获取默认的路由信息,如果 isDefault = true,则尝试获取【默认主题】的路由信息, Topic 名称为 TBW102(与 Broker 注册的默认主题的路由名称相同)

创建路由信息(Broker)

Broker 接收到消息之后,会先检查消息的 Topic 是否存在;如果消息对应的 Topic 不存在,且 Broker 允许自动创建不存在的 Topic,则会自动创建 Topic。

1.先检查 Topic 的路由信息是否存在,如果不存在,则自动创建 Topic

2.具体自动创建 Topic 的操作,通过检查路由信息中是否包含【默认主题】的路由来判断 Broker 是否开启了自动创建 Topic

整体流程

我把自动创建 Topic 的流程概括为【偷梁换柱】,这个活是由 Broker,NameServer,生产者配合完成的

  • 生产发送消息时,如果指定的 Topic 不存在,NameServer 会返回一个【默认主题】的路由信息,使得生产者能够正常发生消息

  • Broker 收到消息后,发现消息对应 Topic 不存在,且 Broker 允许自动创建 Topic,则会为消息创建 Topic ,并定时把路由信息同步至 NameServer

  • 生产者也会定时从 NameServer 同步最新的路由信息,缓存至本地

  • 后续生产者发送消息时,就可以从本地的缓存中查询到对应 Topic 的路由信息了

问题解决

了解了 Broker 自动创建 Topic 的原理,很快便解决了我的问题。

为什么即使 Broker 配置了自动创建不存在的 Topic,发送消息时还是会出现 Topic 路由信息无法获取的现象? 原因如下

  • 发送消息的 demo 中引入的 RocketMQ 版本为 4.3.0
  • 本地启动的 Broker 服务,RocketMQ 版本为 4.9.1
  • 两个版本中对于【默认主题】的命名不一致,所以导致 Broker 虽然向 NameServer 注册了【默认主题】的路由信息,生产者也获取不到

4.3.0 版本【默认主题】的名称为【AUTO_CREATE_TOPIC_KEY】

4.9.1 版本【默认主题】的名称为【TBW102】

因为 Broker 服务是通过本地源码启动的,于是我更改了源码中对于【默认主题】命名,使得两边【默认主题】的命名保持一致,并重新启动 Broker 服务

生产者成功发送消息,问题解决。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐