当前位置: 首页 > 科技观察

NameServer核心原理解析

时间:2023-03-17 13:04:25 科技观察

本文转载自微信公众号《SH的全栈笔记》,作者SH的全栈笔记。转载本文请联系SH全栈笔记公众号。上一篇文章介绍了Broker、Producer和Conusmer的一些源码和核心机制,但实际上RocketMQ中还有一个我们通常忽略的关键组件——NameServer。在日常使用中,我们接触最多的是Producer和Consumer,而NameServer并不直接与我们进行交互。就像Kafka集群背后的Zookeeper集群对其集群元数据进行管理一样,NameServer也支持其背后RocketMQ的正常工作。你给译者翻译一下,什么是NameServerNameServer,你可以简单理解为注册中心。当Broker启动时,它会将自己注册到NameServer上,同时将Broker的IP地址、端口相关数据、Broker中存储的RocketMQ集群路由数据连同心跳发送给NameServer。这里的路由信息??是指Topic下的MessageQueue在哪个Broker上。Producer会从NameServer获取元数据,然后将Message发送给对应的Broker。相应的,Consumer也需要从NameServer获取数据。通常我们配置消费者,里面主要有两个重要的信息,分别是你要消费的主题和当前消费组。Consumer会根据配置去NameServer获取对应的Topic有哪些Brokers,它的真实IP地址和端口是多少,获取到后就可以开始消费消息了。注册经纪人做了什么?这里我们先通过注册Broker的源码来预热,为后面阅读整个部分的源码做准备,直接上传代码。首先,这里是Broker版本的区分。不同的版本采用不同的处理方式。由于官网最新版本已经到了4.9.0,所以我们暂时不考虑低版本的情况。我们以后有时间再讨论。只贴出上面几行代码给大家,其余的代码尽量用流程图来代替验证Body的完整性。首先是验证Broker传递的数据的完整性。很简单的判断,将Broker传过来的Body用CRC32算法加密后,与请求中Header中Broker加密后的值进行比较。如果不同,说明数据的完整性有问题,需要中断注册流程。这里解析Body分为两种情况:Body为空和Body不为空如果Body为空,则重置当前注册的Broker的DataVersion;而**Body不为空**,会解析Body,主要是从中解析出DataVersion,代表Broker中的数据版本。其次,解析出Broker中存储的所有Topic及其相关配置。执行注册逻辑这是注册的核心逻辑。为了更容易理解,我们将情况分开讨论,以免将两种情况混为一谈。首次注册对于集群中Broker'sName的非首次注册维护,在整个操作开始前,会在RouteInfoManager上加一把锁。这个RouteInfoManager是NameServer存储数据的地方。这个锁是一个读写锁,使用Java中的ReentrantReadWriteLock。这里的BrokerName是RocketMQ配置文件中配置的一个变量。用于标识一个Broker名称,但是我们知道Broker是主从架构,RocketMQ4.5之后推出的Dleger可以实现一主多从。也就是说,一个BrokerName可能对应多个Broker实例。从MQ的角度来看,Broker是多实例部署的;从Producer或Consumer的角度来看,只有一个Broker。所以这一步维护的是当前集群中有多少这样的BrokerName。维护Broker数据然后,RocketMQ会在brokerAddrTable中维护每个Broker的核心数据,包括:Broker所在的集群Broker的名称(上面刚刚讨论过)所有Broker的BrokerID和Address的对应关系,即aMap,Address是UndersameBrokerNameIP+port,为什么会有多个地址信息在上一步已经回答了,这里不再赘述。Broker数据维护主要有两个方面:brokerAddrTable中是否存在broker数据brokerAddrTable中维护的数据不能有重复的地址信息第一个过于基础简单,这里不再赘述。让我们关注第二点。我们知道一个Map中会存储多个Broker地址,因为Broker是基于主从架构的。那不知道大家有没有想过NameServer是如何区分主从的呢?答案是通过地图的钥匙。如果为0表示Master节点,1表示Slave节点,因为RocketMQ本身实现的Broker主从架构是一主一从,而一主多从是Dleger实现的,增加了RocketMQ4.5以后,暂不讨论。区分的逻辑是这样的:什么时候会出现重复?答案是主从切换。例如,假设一个SlaveBroker的地址为192.168.1.101:8081并且已经注册。此时brokerAddrs中已经有key:1value:192.168.1.101:8081的记录。当集群中的Master宕机时,它会从故障中恢复。假设选择上面的Broker作为新的Master,注册的时候会发现brokerAddrs中已经有相同的Address,只是Key不同。但是,由于它们本质上是同一台机器,如果key为1,即角色为Slave的记录没有被移除,就会造成数据一致性问题。简单总结一下,同一个Adreess只能存在于一个brokerAddrs中。有兴趣的可以看看源码。其实上面描述的逻辑是一样的。去掉重复的Address数据后,注册的Broker数据就会注册到brokerAddrs中。这里维护MessageQueue数据主要是根据Broker数据更新其MessageQueue相关数据。接下来我们详细分析一下MessageQueue的维护过程。还将给出源代码和流程图。两部分是等价的,可以选择性查看。Master节点注册时,如果是第一次注册或者数据有更新,会调用一个方法createAndUpdateQueueData维护MessageQueue相关数据。这里数据是否更新的判断是基于DataVersion,代表Broker数据的版本。之后通过TopicName获取对应的MessageQueue列表。这里可能会有一些疑问。一个Topic不应该只有一个MessageQueue相关的配置吗?为什么这里有一个列表?小,布局小。Topic是一个逻辑基于上面的概念,一个Topic的MessageQueue会分布在不同的Brokers上,所以这里列出一个列表。更新过程如上图所示。拿到MessageQueue列表后,会和本次注册的Broker中的MessageQueue数据进行比对。如发现有差异,将全额更换。没有其他复杂的比较逻辑。源码和上图一样,有兴趣的可以自行查看。维护Broker的生存信息就在这里,处理MessageQueue相关的逻辑。接下来,NameServer将更新brokerLiveTable中的数据,该表存储了所有当前活跃的Brokers。这块的作用后面会讲到。NameServer启动流程通过了解注册Broker的整个过程,我们对整个NameServer的架构有了一个大概的了解,然后再从一个整体的角度来看待NameServer。上图中已经给出了NameServer主进程的整体流程,所以就不放源码了,意义不大。下面说说扫描不再活跃的Broker。这个后台线程将每10秒执行一次。这里会遍历上面提到的brokerLiveTable,因为这里维护了所有活跃的Broker。如果一个Broker超过120秒没有向NameServer发送心跳,它将被从brokerLiveTable中移除。NameServer可以处理的操作简单了解一下注册Broker的过程。其实NameServer还支持很多其他的操作,这里不再一一列举。读是没有意义的。如果你有兴趣,你可以在网上找到很多他们的资料。而且RegisterBroker的操作所涉及到的源码中的数据结构,在其他操作中都会用到,所以理解了RegisterBroker之后,再去阅读其他操作的源码也会很顺畅。