NameServer启动流程
NameServer是一个提供轻量级服务发现和路由的服务器,主要功能
- 代理管理,
NameServer从Broker集群接受注册,提供心跳机制来检查Broker是否活动。 - 路由管理,每个名称服务器将保存关于
Broker集群的整个路由信息和用于客户机查询的队列信息。
作为RocketMQ的注册中心,NameServer接收集群中所有Broker的注册,并每隔10s提供心跳机制来检查Broker的是否,如果Broker有超过120s没有更新,那么将被视为失效并从集群中移除。


NamesrvStartup启动入口
public static NamesrvController main0(String[] args) { try { NamesrvController controller = createNamesrvController(args); start(controller); String tip = "The Name Server boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer(); log.info(tip); System.out.printf("%s%n", tip); return controller; } catch (Throwable e) { e.printStackTrace(); System.exit(-1); } return null; }
createNamesrvController方法,就是从命令行接收参数,然后将解析成配置类NamesrvConfig和NettyServerConfig。
final NamesrvConfig namesrvConfig = new NamesrvConfig(); final NettyServerConfig nettyServerConfig = new NettyServerConfig(); nettyServerConfig.setListenPort(9876); if (commandLine.hasOption('c')) { String file = commandLine.getOptionValue('c'); if (file != null) { InputStream in = new BufferedInputStream(new FileInputStream(file)); properties = new Properties(); properties.load(in); MixAll.properties2Object(properties, namesrvConfig); MixAll.properties2Object(properties, nettyServerConfig); namesrvConfig.setConfigStorePath(file); System.out.printf("load config properties file OK, %s%n", file); in.close(); } } if (commandLine.hasOption('p')) { InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME); MixAll.printObjectProperties(console, namesrvConfig); MixAll.printObjectProperties(console, nettyServerConfig); System.exit(0); } MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
-c命令可以指定配置文件,将配置文件中的内容解析成java.util.Properties类,然后赋值给NamesrvConfig和NettyServerConfig类完成配置文件的解析与映射。
NamesrvConfig的配置信息
public class NamesrvConfig { private static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME); 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; }

public class NettyServerConfig implements Cloneable { //NettyServer监听端口 private int listenPort = 8888; //etty默认事件处理线程池,处理如broker注册,topic路由信息查询、topic删除等与producer、broker交互request private int serverWorkerThreads = 8; //事件处理器注册时如果没指定线程池时,使用serverCallbackExecutorThreads指定的公用publicExecutor来处理特定业务交互命令 private int serverCallbackExecutorThreads = 0; //Netty Selector线程数量 private int serverSelectorThreads = 3; //单向发送信号量,防止单向发送请求并发度过高 private int serverOnewaySemaphoreValue = 256; //异步发送信号量,防止单向发送请求并发度过高 private int serverAsyncSemaphoreValue = 64; private int serverChannelMaxIdleTimeSeconds = 120; }
初始化及心跳机制
通过NamesrvController#initialize完成初始化
public boolean initialize() { // 加载`kvConfig.json`配置文件中的`KV`配置,然后将这些配置放到`KVConfigManager#configTable`属性中 this.kvConfigManager.load(); // 根据`NettyServerConfig`启动一个`Netty`服务器 this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService); // 初始化负责处理`Netty`网络交互数据的线程池 this.remotingExecutor = Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new ThreadFactoryImpl("RemotingExecutorThread_")); this.registerProcessor(); // 注册心跳机制线程池 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.routeInfoManager.scanNotActiveBroker(); } }, 5, 10, TimeUnit.SECONDS); // 注册打印KV配置线程池 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { NamesrvController.this.kvConfigManager.printAllPeriodically(); } }, 1, 10, TimeUnit.MINUTES); // 省略以下代码... return true; }
初始化NamesrvController过程中,会注册一个心跳机制的线程池,会在启动后5秒开始每隔10秒扫描一次不活跃的broker
public void scanNotActiveBroker() { Iterator<Entry<String, BrokerLiveInfo>> it = this.brokerLiveTable.entrySet().iterator(); while (it.hasNext()) { Entry<String, BrokerLiveInfo> next = it.next(); long last = next.getValue().getLastUpdateTimestamp(); if ((last + BROKER_CHANNEL_EXPIRED_TIME) < System.currentTimeMillis()) { RemotingUtil.closeChannel(next.getValue().getChannel()); it.remove(); log.warn("The broker channel expired, {} {}ms", next.getKey(), BROKER_CHANNEL_EXPIRED_TIME); this.onChannelDestroy(next.getKey(), next.getValue().getChannel()); } } }
RouteInfoManager#brokerLiveTable属性存储的是集群中所有broker的活跃信息,主要是BrokerLiveInfo#lastUpdateTimestamp属性,它描述了broker上一次更新的活跃时间戳。若lastUpdateTimestamp属性超过120秒未更新,则该broker会被视为失效并从brokerLiveTable中移除。
优雅停机
NameServer启动的最后一步,是注册了一个JVM的钩子函数,会在JVM关闭之前执行。这个钩子函数的作用是释放资源,如关闭Netty服务器,关闭线程池等。
Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable<Void>() { @Override public Void call() throws Exception { controller.shutdown(); return null; } }));
浙公网安备 33010602011771号