RocketMQ-NameServer配置加载、启动源码分析

NameServer作用

在介绍NameServer前,先看下官方的RocketMQ架构图
在这里插入图片描述

NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。主要包括两个功能

  1. Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;
  2. 路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费

NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。Broker是向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer,Consumer仍然可以动态感知Broker的路由的信息

NameServer实例时间互不通信,这本身也是其设计亮点之一,即允许不同NameServer之间数据不同步(像Zookeeper那样保证各节点数据强一致性会带来额外的性能消耗)

本文会从源码角度重点分析NameServer的启动流程

下篇文章会主要分析NameServer对broker数据的管理,以及路由机制

NameServer启动

先给出NameServer启动的时序图,方便大家跟踪流程
在这里插入图片描述

NameServer配置加载

时序图第一步加载配置文件对应源代码在org.apache.rocketmq.namesrv.NamesrvStartup#main0方法中
在这里插入图片描述

从NamesrvConfig,NettyServerConfig中加载配置文件代码在createNamesrvController方法中,看下具体实现
在这里插入图片描述

与配置相关的两个类为NamesrvConfig和NettyServerConfig

NamesrvConfig中属性如下

	//rocketmqHome路径
	private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY, System.getenv(MixAll.ROCKETMQ_HOME_ENV));
	private String kvConfigPath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "kvConfig.json";
    private String configStorePath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "namesrv.properties";
    private String productEnvName = "center";
    private boolean clusterTest = false;
    //是否允许顺序消息,默认不开启
    private boolean orderMessageEnable = false;

NettyServerConfig中配置如下,mq底层基于Netty实现通讯,NettyServerConfig中参数使用会在NettyRemotingServer初始化及启动时做详细介绍,大家先有个大概了解

	//NettyServer监听端口
	private int listenPort = 8888;
	//Netty默认事件处理线程池,处理如broker注册,topic路由信息查询、topic删除等与producer、broker交互request
    private int serverWorkerThreads = 8;
    //与serverWorkerThreads类似,事件处理器注册时如果没指定线程池时,使用serverCallbackExecutorThreads指定的公用publicExecutor来处理特定业务交互命令
    private int serverCallbackExecutorThreads = 0;
    //Netty Selector线程数量
    private int serverSelectorThreads = 3;
    //单向发送信号量,防止单向发送请求并发度过高
    private int serverOnewaySemaphoreValue = 256;
    //异步发送信号量,防止单向发送请求并发度过高
    private int serverAsyncSemaphoreValue = 64;
    //通道空闲时间 默认120秒
    private int serverChannelMaxIdleTimeSeconds = 120;
	//socket发送缓冲区大小
    private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;
    //接收缓冲区大小
    private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;
    private boolean serverPooledByteBufAllocatorEnable = true;
    //是否启用Epoll IO模型,Linux环境建议开启
    private boolean useEpollNativeSelector = false;

在nameServer启动时也可以通过-c命令指定配置文件地址来加载外部配置,至此NameServer配置加载完成,返回一个NamesrvController对象,进入初始化、启动步骤

NameServerController初始化

初始化、启动代码如下
在这里插入图片描述

先看下初始化方法initialize方法,对应时序图中3,4,5,6,7步骤,下面逐个分析

在这里插入图片描述

kvConfig加载

@3:读取kvConfigPath下的文件,并转化成类型为HashMap<String/* Namespace */, HashMap<String/* Key */, String/* Value */>>的Map中,nameServer中相关配置信息存储,均采用线程不安全的HashMap容器存储,结合读写锁ReadWriteLock最大化并发度,KvConfig就是一个典型的例子,后续路由信息的存储也是同理,读写锁如图
在这里插入图片描述

初始化NettyRemotingServer

@4:初始化NettyRemotingServer,对应代码如下,NettyServerConfig为上述提到Netty的配置类,BrokerHousekeepingService实现了ChannelEventListener,用于Channel通道关闭时调用RouteInfoManager#onChannelDestroy清除路由信息

this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);

在这里插入图片描述

下面进到NettyRemotingServer构造方法看下具体内容
在这里插入图片描述
其中publicExecutor会在,注册特定业务Netty事件处理器时用到,特定业务指的是发送消息,查询消息等业务
在这里插入图片描述
具体业务注册事件处理线程池的地方在BrokerController中:
在这里插入图片描述

注册默认事件处理线程池

@5:注册默认事件处理器
在这里插入图片描述
那么什么是默认事件呢?就是Producer,Broker与NameServer的交互事件,如Broker注册,Topic删除等事件,处理默认事件的代码逻辑在DefaultRequestProcessor中,如图所示,大家从名字上就能看出有哪些交互
在这里插入图片描述

定时器scanNotActiveBroker

@6:文章开头提到NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯,那么Broker实例挂掉之后,NameServer如何感知呢?Broker启动时,会开启定时器,定时向每个NameServer进行心跳注册,注册时,会将Broker存活信息存储在RouteInfoManager#brokerLiveTable中

private final HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;

BrokerLiveInfo属性信息如下,关键在于注册时将当前时间存储在了lastUpdateTimestamp字段中

	//上次心跳注册时间
	private long lastUpdateTimestamp;
    private DataVersion dataVersion;
    private Channel channel;
    private String haServerAddr;

回到scanNotActiveBroker中,其定时扫描brokerLiveTable,将过期的broker信息移除
在这里插入图片描述
默认broker失效时间为120秒,超过120秒没收到来自broker的心跳,则清除该 broker路由信息,具体路由相关分析在下篇文章介绍

定时器printAllPeriodically

@7:定时输出kvConfig信息,具体为什么要定时输出,我估计着大概是为了定时查看实时配置信息吧

JVM钩子函数注册

@8:NameServer初始化完后,先向JVM注册一个钩子函数,在JVM关闭时对NameServerController中线程池,NettyServer进行关闭,大家可以借鉴这种写法来关闭自己业务中用到的线程池
在这里插入图片描述
线程池的shutDown方法调用后不再接收新提交的任务,同时等待线程池里的任务执行完毕后关闭线程池
在这里插入图片描述

NameServerController启动

@9:NameServerController启动代码的核心在NettyRemotingServer的start方法中,主要是Netty相关配置

在这里插入图片描述

本文主要介绍了NameServer相关配置及启动流程,NameServer作为路由中心,更重要的自然是NameServer对broker数据的管理,以及路由机制,下篇文章重点介绍这两点

发布了43 篇原创文章 · 获赞 134 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/hosaos/article/details/94158508