RocketMQ5.0 NameServer启动流程
1. NameServer 启动
org.apache.rocketmq.namesrv.NamesrvStartup 的Main函数是启动的入口。
启动分成了两块:
- NameServer启动
- Controller启动(5.0为自动自主切换新增的一个模块,内嵌NameServer的时候会启动)
本篇文章只分析NameServer的启动,Controller的启动在后续的文章中进行分析
1.1 命令行参数解析
NameServer启动之前需要先对命令行参数进行解析,将命令行参数解析为NameServer启动需要的参数配置。主要的命令行参数有两个
命令 | 说明 |
-c | 设置配置文件文件位置 |
-p | 打印配置的参数 |
-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的连接逻辑,这里的客户端包括:生产者、消费者,以及Broker RouteInfoManager 路由管理,主要管理Broker的元数据,Topic的元数据信息
1.3 初始化NamesrvController
首先调用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
这里初始化了两个线程池:
- 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
将线程池和处理器绑定。 Rocketmq5.0版本对处理器进行了线程池隔离,将获取路由相关的处理和其他的处理例如Broker的注册进行线程池的隔离。
1.3.5 startScheduleService
启动三个定时任务,两个是打印的的定时任务没有业务逻辑,只有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 节点可以提高系统的可用性和容错性。