问题现象
RocketMQ部署的双主双从集群,Topic_Test1只存在于其中一台主节点broker-a上,从而该Topic发送的消息只会发送到了broker-a节点,另一台主节点broker-b等于是“隔岸观火”没有发挥任何作用。
问题分析
我们在发送Topic_Test1主题消息时,MQ集群里并存在Topic_Test1这个主题,Broker参数autoCreateTopicEnable默认为true,会自动创建不存在的Topic。
这里补充一下RocketMQ路由获取规则的知识:
- Broker 在启动时会向 Nameserver 注册其存储的路由信息,并持续每30秒发送心跳包,同时更新路由信息。
- Nameserver 则每10秒扫描一次路由表。一旦发现 Broker 服务出现故障,对应的路由信息将被移除。
- 消息生产者每30秒会从 Nameserver 重新获取 Topic 的路由信息,并更新其本地路由表。在发送消息之前,如果本地路由表中缺少特定主题的路由信息,生产者会主动从 Nameserver 拉取该主题的消息。
现在生产者在发送消息的时候,肯定是获取不到这个未创建Topic的路由信息的,那么它会如何处理呢?
源码
没有什么是比源码更能说明问题的,我们直接看源码吧。 RocketMQ版本:5.1.0
既然是双主集群,那么两台主Broker应该都会创建这个默认主题的,我们继续看生产者是如何发送这个Broker上不存在的Topic信息发送出去的吧。
这里只有一个默认的Topic信息,后面会自动创建Topic_Test1主题的路由信息
默认的主题在两台主节点都存在,这里选择其中一个队列
我们继续看服务端是如何处理这个消息的
服务端发现主题不存在后,会自动创建,等下次往Nameserver发送路由心跳的时候,就会带上这个自动创建的主题信息。而当前因为发送的消息量比较少,另一台主节点此时还是没有Topic_Test1这个主题的,后续发送方从Nameserver处获取到的Topic_Test1主题的路由信息只有其中一个主节点队列,导致无论再发多少条消息,都只会发往其中一台主节点。
到这里,问题已经很清晰了,我们再做个实验验证一下,一次发送10条消息(超过8条)。
总结:
生产环境中,一定要关闭自动创建主题(autoCreateTopicEnable=false),当业务需要新建主题时,选择手动创建,如果不关闭,在第一次发送消息量比较少时,则可能出现某个主节点无该主题。