RocketMQ梳理 - namesrv

一、前言

最近实习用到了rocketmq,在完成项目后,心血来潮,突然想深入地了解一下rocketmq,特在此记录一下。

本文结合rocketmq官方文档和网上的一些零零散散的资料,常识去简单梳理rocketmq整体执行流程,作为个人学习历程的记录。

二、整体模块如下

image-20231127105106106

这是从gitHub上down下来的rocketmq源码,可以大致分为以下模块:

  1. rocketmq-namesrv:namesrv服务,更新和路由发现 broker服务。
  2. rocketmq-broker:mq的核心,主要做消息存储,可以接收consumer和producer的请求,然后通过调用rocketmq-store服务对消息进行处理。
  3. rocketmq-store:存储层实现。
  4. rocketmq-remoting:基于netty的底层通信实现,rocketmq的底层实现。
  5. rocketmq-common:common服务,比如一些配置文件、常量。
  6. rocketmq-client:java版本的mq客户端。
  7. rocketmq-filter:消息过滤服务,相当于在broker和consumer中间加入了一个filter代理。
  8. rocketmq-srvutil:解析命令行的工具类ServerUtil。
  9. rocketmq-tools: mq集群管理工具,查询rocketmq的一些信息,如topic、message等

三、NameSrv源码分析

以下是namesrv的总入口,主要是要初始化两个类,NamesrvControllerControllerManager

  1. NamesrvController:NamesrvController是RocketMQ中的Name Server模块的控制器,负责管理Name Server节点的状态消息的路由注册查询等功能。它通过监控集群中所有的Name Server节点,并维护一张路由信息表,用于提供消息发送者和接收者之间的消息路由信息。NamesrvController还负责处理新的Name Server节点加入和退出集群时的动态路由更新
  2. ControllerManager:ControllerManager是RocketMQ中的Controller模块的管理器,负责管理Broker、Topic、Cluster等元数据信息的变更和路由计算。ControllerManager通过选举产生一个Controller节点,该节点负责管理整个集群的元数据信息,并保证集群中各个Broker节点之间的状态一致性。ControllerManager通过心跳检测元数据同步等机制来实现集群中元数据的一致性和可靠性

总的来说,NamesrvController主要负责管理Name Server节点的状态和消息路由信息,而ControllerManager则负责管理整个集群的元数据信息和路由计算。它们分别在RocketMQ的Name Server和Broker集群中扮演着重要的角色,确保了RocketMQ集群的稳定性和可靠性。

image-20231127110500654

我们先来看NamesrvController的初始化,先是读取命令行和配置文件信息,为后续初始化做铺垫。

image-20231127111432393

image-20231127111155609

之后进行一系列基础组件的初始化,此处的loadConfig,就是依赖前面的namesrvConfig,之后就是初始化网络组件、线程池、registerProcessor等。

image-20231127111559360

这里主要说一下上面的定时任务,我们知道namesrv是靠心跳机制去感知broker的,namesrv启动后,会一直监听,等待broker、producer、comsumer连接。broker在启动时向所有namesrv注册,生产者在发送消息之前先从namesrv获取broker服务器地址列表,然后根据负载均衡算法从列表中选择一台服务器进行消息发送。消费者在订阅某个主题的消息之前从namesrv获取broker服务器地址列表(有可能是集群),但是消费者选择从broker中订阅消息,订阅规则由 broker 配置决定。

可以说namesrv就是rocketmq的大脑,用于把broker、producer、consumer三者串联起来,这里就涉及到路由注册了。因为broker启动后向所有namesrv发送路由,然后通过心跳机制与namesrv之间维持一个长连接,当broker挂了后就需要把它从namesrv中剔除掉。

image-20231127112449538

image-20231127112518324

可以看到,namesrv每10s都会去brokerLiveTable去找超时的broker,并把相应的channel给关闭,然后将其从路由表中去除掉。

之后就是启动namesrv了,本质就是启动nettyServer与nettyClient。

image-20231127113109613

这里我们看看这个routeInfoManager,因为我们之前namesrv剔除超时的broker时也用到了它。routeInfoManager主要用于路由管理,消息发送时客户端会从namesrv获取路由信息,同时broker会定时更新namesrv的路由信息。

image-20231127114006995

image-20231127114042195

image-20231127114110407

我们从routeInfoManager中随便截了几个方法,可以看到它们都有一个共同点,都用到了锁,而且是读写锁

因为我们之前说过,路由表上的操作可能非常频繁,消费者发送消息时需要获取topic列表,broker需要定时向namesrv发送心跳以维持长连接,需要频繁地读写路由表,所以这里用到了读写锁。

我们还可以观察到routeInfoManager了很多信息,topic消息队列路由信息、broker地址、cluster等等,但它们都有一个共同特点,就是内存存储,我们在前面分析模块时提到过,rocketmq-broker借助rocketmq-store模块做持久化存储,rocketmq-namesrv是没有持久化的功能的,这样设计可以提高namesrv的处理能力,专注于其“大脑”的功能。

image-20231127115444987