1. NameServer 启动
org.apache.rocketmq.namesrv.NamesrvStartup 的Main函数是启动的入口。
![](https://img.haomeiwen.com/i28888492/eb00922fead651bf.png)
启动分成了两块:
- NameServer启动
- Controller启动(5.0为自动自主切换新增的一个模块,内嵌NameServer的时候会启动)
本篇文章只分析NameServer的启动,Controller的启动在后续的文章中进行分析
1.1 命令行参数解析
NameServer启动之前需要先对命令行参数进行解析,将命令行参数解析为NameServer启动需要的参数配置。主要的命令行参数有两个
![](https://img.haomeiwen.com/i28888492/4fffb4f8da467f89.png)
-c命令行参数设置配置文件位置,然后将配置文件中的参数值解析设置为配置类的属性值,涉及到的配置有如下几个:
- NamesrvConfig
- NettyServerConfig
- NettyClientConfig
- ControllerConfig(只有当Controller内嵌NameServer的时候才起作用)
namesrvConfig = new NamesrvConfig();
nettyServerConfig = new NettyServerConfig();
nettyClientConfig = new NettyClientConfig();
nettyServerConfig.setListenPort(9876);
controllerConfig = new ControllerConfig();
if (commandLine.hasOption('c')) {
String file = commandLine.getOptionValue('c');
if (file != null) {
InputStream in = new BufferedInputStream(Files.newInputStream(Paths.get(file)));
properties = new Properties();
properties.load(in);
MixAll.properties2Object(properties, namesrvConfig);
MixAll.properties2Object(properties, nettyServerConfig);
MixAll.properties2Object(properties, nettyClientConfig);
MixAll.properties2Object(properties, controllerConfig);
namesrvConfig.setConfigStorePath(file);
System.out.printf("load config properties file OK, %s%n", file);
in.close();
}
}
更多的参数设置修改可以参照源码中NamesrvConfig、NettyServerConfig、NettyClientConfig、ControllerConfig中的类属性。
1.2 创建NamesrvController
根据NamesrvController的构造函数创建了三个重要的管理类实例:
- KVConfigManager
- BrokerHousekeepingService
- RouteInfoManager
KVConfigManager KV的持久化、序列化和反序列化处理BrokerHousekeepingService处理客户端和NameServer的连接逻辑,这里的客户端包括:生产者、消费者,以及BrokerRouteInfoManager路由管理,主要管理Broker的元数据,Topic的元数据信息
1.3 初始化NamesrvController
![](https://img.haomeiwen.com/i28888492/603fe1e81934b6f6.png)
首先调用NamesrvController#initialize进行初始化,我们看一下初始化做了什么事情。
public boolean initialize() {
loadConfig();
initiateNetworkComponents();
initiateThreadExecutors();
registerProcessor();
startScheduleService();
initiateSslContext();
initiateRpcHooks();
return true;
}
1.3.1 loadConfig
1.3.2 initiateNetworkComponents
private void initiateNetworkComponents() {
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
this.remotingClient = new NettyRemotingClient(this.nettyClientConfig);
}
创建NameServer的网络服务,以及NameServer的客户端。
1.3.3 initiateThreadExecutors
![](https://img.haomeiwen.com/i28888492/6ffc2aeb14dcb006.png)
这里初始化了两个线程池:
- clientRequestExecutor线程池处理客户端(生产者和消费者)获取Topic的路由信息(RequestCode.GET_ROUTEINFO_BY_TOPIC)
- defaultExecutor线程池处理除了RequestCode.GET_ROUTEINFO_BY_TOPIC以外的请求。
:::tip 在5.0版本后多了一个clientRequestExecutor线程池,主要是因为增加NameServer的可用性,即使defaultExecutor不能正常工作出现宕机的情况,客户端仍然可以获取Topic的路由信息而进行的线程池的隔离。 具体可以参照[RIP-29] :::
1.3.4 registerProcessor
![](https://img.haomeiwen.com/i28888492/2b16f4e5324d2346.png)
将线程池和处理器绑定。 Rocketmq5.0版本对处理器进行了线程池隔离,将获取路由相关的处理和其他的处理例如Broker的注册进行线程池的隔离。
1.3.5 startScheduleService
![](https://img.haomeiwen.com/i28888492/cc1bf6ead14c76a3.png)
启动三个定时任务,两个是打印的的定时任务没有业务逻辑,只有scanNotActiveBroker定时任务的作用:默认每5秒扫描一次Broker是否过期。
1.3.5 initiateSslContext
初始化SsL
1.3.6 initiateRpcHooks
private void initiateRpcHooks() {
this.remotingServer.registerRPCHook(new ZoneRouteRPCHook());
}
目前只注册了一个ZoneRouteRPCHook,主要用于区域路由。
1.4 启动NamesrvController
public void start() throws Exception {
this.remotingServer.start();
// In test scenarios where it is up to OS to pick up an available port, set the listening port back to config
if (0 == nettyServerConfig.getListenPort()) {
nettyServerConfig.setListenPort(this.remotingServer.localListenPort());
}
this.remotingClient.updateNameServerAddressList(Collections.singletonList(NetworkUtil.getLocalAddress()
+ ":" + nettyServerConfig.getListenPort()));
this.remotingClient.start();
if (this.fileWatchService != null) {
this.fileWatchService.start();
}
this.routeInfoManager.start();
}
启动NameServer的Netty对外的服务和客户端服务,在文件监控服务不为空的情况下启动服务。 路由管理服务启动: 主要是启动了批量注销服务。到这里整个服务就已经启动完成。
2. 总结
- 启动参数解析:NameServer 启动时需要指定一些参数,例如监听端口、RocketMQ 集群的名称等等。NameServer 会先解析这些参数,并根据这些参数进行初始化。
- 加载配置文件:NameServer 还会加载配置文件,包括 broker 配置、路由配置、Topic 配置等等,这些配置文件可以指定在启动参数中,也可以在启动后进行修改。
- 创建 MBeanServer:NameServer 还会创建一个 MBeanServer,用于对 NameServer 进行监控和管理。
- 启动 Netty 服务端:NameServer 的主要功能是接收 Broker 节点的注册请求和心跳信息,并维护 Broker 节点的状态。为此,NameServer 会启动一个 Netty 服务端,用于接收和处理这些请求。
- 注册 ShutdownHook:NameServer 还会注册一个 ShutdownHook,用于在 NameServer 关闭时执行一些清理工作,例如关闭 Netty 服务端、保存路由信息等等。
- 初始化定时任务:NameServer 还会初始化一些定时任务,例如定时刷新路由信息、定时清理过期的 Broker 节点等等。这些定时任务是通过 Java 自带的 ScheduledExecutorService 实现的。
- 启动完成:最后,NameServer 启动完成,并等待 Broker 节点的注册和心跳信息。
以上就是 RocketMQ NameServer 的启动流程。需要注意的是,RocketMQ 集群中至少需要一个 NameServer 节点,多个 NameServer 节点可以提高系统的可用性和容错性。
网友评论