对于一个消息队列集群来说,系统由很多台机器组成,每个机器的角色、IP 地址都不相同,而且这些信息是变动的。这种情况下, 如果一个新的Producer 或Consumer 加入,怎么配置连接信息呢?NameServer 的存在主要是为了解决这类问题,由NameServer 维护这些配置信息、状态信息,其他角色都通过NameServer 来协同执行。
4.1 NameServer 的功能
NameServer 是整个消息队列中的状态服务器,集群的各个组件通过它来了解全局的信息。同时,各个角色的机器都要定期向NameServer 上报自己的状态,超时不上报的话, NameServer 会认为某个机器出故障不可用了,其他的组件会把这个机器从可用列表里移除。
NamServer 可以部署多个,相互之间独立,其他角色同时向多个NameServer机器上报状态信息,从而达到热备份的目的。NameServer 本身是无状态的,也就是说NameServer 中的Broker 、Topic 等状态信息不会持久存储,都是由各个角色定时上报并存储到内存中的( NameServer 支持配置参数的持久化,一般用不到) 。
4.1.1 集群状态的存储结构
在org.apache.rocketmq.namesrv.routeinfo 的Rou telnfoManager 类中,有五个变量,集群的状态就保存在这五个变量中。
4.1.2 状态维护逻辑
本节基于源码分析NameServer 如何维护各个Broker 的实时状态,如何根据Broker 的情况更新各种集群的属性数据。因为其他角色会主动向Name Server 上报状态,所以NameServer 的主要逻辑在DefaultRequest Processor类中,根据上报消息里的请求码做相应的处理, 更新存储的对应信息。
当NameServer 和Broker 的长连接断掉以后, onChannelDestroy 函数会被调用,把这个Broker 的信息清理出去。
NameServer 还有定时检查时间戳的逻辑, Broker 向NameServer发送的心跳会更新时间戳, 当NameServer 检查到时间戳长时间没有更新后,便会触发清理逻辑。从代码可以看出是每10 秒检查一次,时间戳超过2 分钟则认为Broker 已失效。
4.2 各个角色间的交互流程
下面从Topic 的创建入手,结合源码分析一下NameServer 如何和其他各个组件交互,以及NameServer 存储的元数据内容的具体含义。
4.2.1 交互流程源码分析
这里是一堆代码,不贴出了,说下大概意思。
Topic的创建需要指定b和c两个参数,而且他们俩只有一个会起作用( -b 优先), b 参数指定在哪个Broker 上创建本Topic 的Message Queue , c 参数表示在这个Cluster 下面所有的Master Broker 上创建这个Topic 的Message Queue , 从而达到高可用性的目的。具体的创建动作是通过发送命令触发的。
在Nameserv执行创建Topic的命令后,命令会被发送到对应的Broker上,Broker 接到创建Topic 的请求后,执行具体的创建逻辑。其中最后一步是向NameServer 发送注册信息, NameServer 完成创建Topic 的逻辑后,其他客户端才能发现新增的Topic。
4.2.2 为何不用ZooKeeper
ZooKeeper 是Apache 的一个开源软件,为分布式应用程序提供协调服务。那为什么RocketMQ 要自己造轮子,开发集群的管理程序呢?答案是ZooKeeper 的功能很强大,包括自动Master选举等, RocketMQ 的架构设计决定了它不需要进行Master 选举,用不到这些复杂的功能,只需要一个轻量级的元数据服务器就足够了。
中间件对稳定性要求很高, RocketMQ 的NameServer 只有很少的代码,容易维护,所以不需要再依赖另一个中间件,从而减少整体维护成本。
4.3 底层通信机制
分布式系统各个角色间的通信效率很关键,通信效率的高低直接影响系统性能,基于Socket 实现一个高效的TCP 通信协议是很有挑战的,本节介绍RocketMQ 是如何解决这个问题的。
好吧,这里基本都是代码,不介绍了。
4.4 本章小结
本章介绍了NameServer 的功能, NameServer 在RocketMQ 集群中扮演调度中心的角色。各个Producer 、Consumer 上报自己的状态上去,同时从Name Server 获取其他角色的状态信息。NameServer 的功能虽然非常重要,但是被设计得很轻量级,代码量少并且几乎无磁盘存储,所有的功能都通过内存高效完成。本章还介绍了底层的通信机制, RocketMQ 基于Netty 对底层通信做了很好的抽象,使得通信功能逻辑清晰,代码简单。Netty 的介绍和具体的通信实现可以查看第13 章。
网友评论