RocketMQ中的路由中心NameServer

RocketMQ的路由中心采用了自研的NameServer,提供了路由管理、服务注册、服务发现的功能。NameServer集群间互不通信。

先简单了解一下这三种能力的实现方式,后面会有源码分析。
路由管理:通过配置文件灵活加载配置。
服务注册:Broker在启动时向所有的NameServer心跳语句,每隔30S向所有NameServer发起心跳包。NameServer收到心跳包后更新缓存。NameServer每隔10S扫描brokerLiveTable,如果连续120S没有收到心跳包,则NameServer移除Broker的路由信息同时关闭Socket连接。
服务发现:RocketMQ的路由发现是非实时的。当topic对应的路由信息发生变化,NameServer并不会通知给客户端。而是由客户端定时拉取Topic对应的最新路由。不实时的路由发现引起的问题由客户端进行解决,保证了NameServer逻辑的简洁。

在分析源码前,其实我们还有一个绕不过去的疑惑,RocketMQ为什么没有采用Zookeeper作为路由中心呢?NameServer集群间互不通信,不具备选主功能,功能不是弱了吗?
其实正是因为RocketMQ的架构导致其不需要Zookeeper提供的“复杂”功能,NameServer完全够用。且因为其不复杂,性能更加高效。

我们对比一下kafka和RocketMQ的架构,能对这个问题有一个更清晰的认识。
图中椭圆表示逻辑概念,方块表示物理概念。
RocketMQ
RocketMQ中的master和slave可以认为是物理上的概念。一台机器要么是master,要么是slave,与topic无关,是在配置文件中指定的(也可以换种方式理解,认为master和slave是逻辑上的概念,broker是物理上的概念。但是一个broker要么是master,要么是slave)。master与slave通过配置brokerName来进行配对。相同的brokerName中,brokerId为0的表示master,其他表示slave。
示例图中有9台broker机器。
RocketMQ中的路由中心NameServer
kafka
kafka中的master和slave可以认为是逻辑上的概念。一个broker上可以部署master,也可以部署slave。
示例图中有3台broker机器。
RocketMQ中的路由中心NameServer
我们可以看出其中较为关键的差异,kafka的master与slave是由选举产生的,需要zookeeper提供的选举机制。RocketMQ的master与slave是由配置确认的,一旦确认不会改变。

实际上,在早期的RocketMQ版本中,路由中心就是由zookeeper实现的,后来由于上述原因,改成了更高效的NameServer。

NameServer的启动流程
NameServer启动时,会加载配置文件,加载KV配置,进行一些初始化动作。
同时会开启两个定时任务,分别做Broker的清理和KV配置信息的打印。
RocketMQ中的路由中心NameServer
路由注册
路由注册在broker启动时触发,broker启动时会和所有NameServer创建心跳连接,向NameServer发送Broker的相关信息。
NameServer在RouteInfoManager类中维护了Broker相关信息的缓存,进行更新动作。更新时用了读写锁,既保证了极高并发场景下的读效率,又避免了并发修改缓存。

RocketMQ中的路由中心NameServer
路由删除
路由删除的触发点有两个:
1)NameServer启动时开启的定时任务,每隔10s扫描一次brokerLiveTable,检测上次心跳包与当前系统时间差,如果时间差大于120s,则移除Broker的相关信息。
2)Broker正常关闭,会向NameServer发送UNREGISTER_BROKER消息。

实现上和注册类似,加读写锁,维护相关的缓存信息,这里就不画图了。

路由发现
客户端定时向NameServer发起请求GET_ROUTEINFO_BY_TOPIC,获取对应的信息。流程较为简单,这边不画图了。

总结
通过本文的探讨,我们大概了解了RocketMQ路由中心提供的功能、实现的方式,我们还了解了没有使用zookeeper的原因。
路由发现的不实时性可能会给小伙伴们带来疑惑,Broker故障期间,发送者向故障Broker上发送消息会导致失败,这种情况RocketMQ是怎么处理的?
其实在前文《RocketMQ中的顺序消息》中有所提及,感兴趣的小伙伴可以再了解一下。