NameServer启动流程

      NameServer是一个提供轻量级服务发现和路由的服务器,主要功能

  • 代理管理,NameServerBroker集群接受注册,提供心跳机制来检查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方法,就是从命令行接收参数,然后将解析成配置类NamesrvConfigNettyServerConfig

        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类,然后赋值给NamesrvConfigNettyServerConfig类完成配置文件的解析与映射。

      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;
            }
        }));

  

 

posted on 2022-05-09 11:39  溪水静幽  阅读(151)  评论(0)    收藏  举报