RocketMq源码解析-路由中心

261 阅读5分钟

这是我参与更文挑战的第5天,活动详情查看: 更文挑战

继续分享RocketMq的路由中心NameServer。

目录

1、架构设计

2、路由元数据

3、路由注册

4、路由删除

5、路由发现

6、小结与思考

一、架构设计

image.png

1、通过上图我们可以知道,NameServer连接着broker、生产者、消费者。broker在启动的时候会向所有的NameServer注册,消息生产者(producer)在消息发送之前会先去NameServer获取broker的服务器列表,然后再根据负载均衡的算法选择一台broker执行消息发送。NameServer与每一台broker都保持着长连接,并间隔30s检测broker是否存活,如果检测到broker宕机,则从路由列表中将其移除,但是不会立即通知消息生产者(producer),这也是为了降低NameServer实现的复杂性,而通过在消息发送端提供容错机子来保证消息发送的高可用。所以rocketMq之所以会选择重新造一个轮子,就是为了尽最大的可能来简化设计并实现高可用。

2、NameServer自身的高可用则是通过多台部署来实现,但是彼此之间又不互相通信,这里就是跟ZK的最大区别,ZK是一个标准的CP系统,但是对于注册中心来说,高可用比一致性在取舍的时候相对会更看重一些,对于消息发送来说,NameServer集群之间的元数据短时间的不一致并不会受到影响,但是这对于NameServer的设计复杂度就简化了太多了,同时因为集群内部不用通信,而对于网络带宽的要求来说也是降低了不少。

二、路由元数据

image.png

 1、topicQueueTable: topic消息队列路由信息,消息发送时根据路由表进行负载均衡
 2、brokerAddrTable: broker的基础信息包含brokerName、所属集群名称、主备broker地址
 3、clusterAddrTable: broker集群节点信息,存储集群中所有broker的名称(存疑)
 4、brokerLiveTable: broker状态信息,NameServer每次收到心跳包后就会替换此信息
 5、filterServerTable: broker上的FilterServer列表,用于类模式消息过滤,(关于类模式消息过滤后续会再讲解)
三、路由注册

rocketMq的路由注册是通过brokerNameServer的心跳功能实现的,broker启动的时候向NameServer集群的所有NameServer发送心跳语句,然后每隔30s向所有的NameServer发送心跳包。NameServer收到心跳包后会更新brokerLiveTable中的BrokerLiveInfo的lastUpdateTimestamp,然后NameServer每隔10s扫描brokerLiveTable,如果发现连续120s都没有更新lastUpdateTimestamp的broker,NameServer将移除该broker并关闭与此broker的socket长连接

1、broker发送心跳包
2、NameServer处理心跳包

设计亮点:

    NameServer与Broker保持长连接,Broker状态存储在brokerLiveTable中,NameServer每收到一个心跳包,将更新brokerLiveTable中关于Broker的状态信息以及路由表(topicQueueTable、brokerAddrTable、brokerLiveTable、filterServerTable)。更新这个路由表(HashTable)使用的是粒度较小的读写锁,允许多个消息发送者(producer)并发读,保证消息发送时的高并发,但是同一时刻NameServer只处理一个心跳包,多个心跳包串行执行。
四、路由删除
1、关于路由删除,rocketMq有两个触发点来触发:
            第一个就是上文介绍的在路由注册后,NameServer会每隔10秒定时扫描brokerLiveTable,如果brokerLiveTable中存在lastUpdateTimestamp时间戳距离当前时间大于120s的broker,则认为该broker失效,并移除该broker,关闭与此broker的长连接,同时更新topic路由表(topicQueueTable)、broker基础信息表(brokerAddrTable)、broker状态信息表(brokerLiveTable)、filterServerTable等表,cluster集群信息表(clusterAddrTable)会通过判断此broker移除后此broker下是否还存在其他可用broker,不存在则会删除此broker,这时集群信息表会判断删除此brokerName后该集群节点是否还存在其它brokerName,不存在则删除此集群节点
            第二个是broker在正常关闭的情况下,会执行unregisterBroker指令,具体操作逻辑同上
2、逻辑步骤:
            1、申请写锁
            2、维护brokerAddrTable,从brokerAddrTable的brokerData的brokerAddrs中找到具体的broker并移除,如果移除后brokerData中没有其他broker,则在brokerAddrTable中的brokerName对应的brokerData集合中移除此brokerData,如果移除后此brokerData后brokerName对应的brokerData为空,则将brokerAddrTable中的brokerName移除
            3、根据brokerName从cluster集群信息表中(clusterAddrTable)找到对应的broker并移除,如果移除后该集群不再包含任何broker,则将该集群从clusterAddrTable中移除
            4、根据brokerName遍历topic路由表(topicQueueTable)所有topic的队列,如果队列中存在此broker,则移除,移除后如果队列中不再包含其他broker,则将此topic移除
            5、释放锁,完成路由删除

五、路由发现

image.png rocketMq的路由发现是非实时的,这个在最开始的时候已经介绍过了,当路由信息发生变更后,NameServer并不会主动推送给客户端,而是由客户端定时拉取topic最新的路由

orderTopicConf : 顺序消息配置内容,来自于kvConfig(存疑)
List<QueueData> queueDatas : topic队列元数据
List<BrokerData> brokerDatas : topic分布的broker的元数据
HashMap<String,List<String>> filterServerTable : broker上过滤服务器地址列表,其中key是brokerAddress,value是filterServer
六、小结与思考

路由注册、发现、删除的机制图如下 :

image.png

这里大家都会发现一个问题:

NameServer至少等待broker失效120秒之后才会将失效的broker剔除,这期间消息生产者会根据topic获取宕机的broker,这样就会导致消息发送失败。具体解决的方式在上一篇结构与设计中也介绍过,即消息重试机制,在消息发送异常时,消息生产者则会重新进行投递,具体的发送过程,在下一篇消息发送中进行细致讲解。