Rocketmq源码分析之NameSrv

73 阅读2分钟

1.NamesrvStartup主函数开始启动服务

public static NamesrvController main0(String[] args) {

    try {
        //根据传入的参数创建控制器
        NamesrvController controller = createNamesrvController(args);
        //开启netty服务
        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方法进入

public static NamesrvController createNamesrvController(String[] args) throws IOException, JoranException {
    //设置当前Rocketmq版本信息
    System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
    //PackageConflictDetect.detectFastjson();
    //构建一些默认的基本选型信息
    Options options = ServerUtil.buildCommandlineOptions(new Options());
    commandLine = ServerUtil.parseCmdLine("mqnamesrv", args, buildCommandlineOptions(options), new PosixParser());
    if (null == commandLine) {
        System.exit(-1);
        return null;
    }
    //创建服务默认的配置信息
    final NamesrvConfig namesrvConfig = new NamesrvConfig();
    //创建netty服务的配置信息
    final NettyServerConfig nettyServerConfig = new NettyServerConfig();
    //设置当前netty服务监听的端口
    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 转换配置信息,也可以叫混合所有信息
            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);
    //如果没有配置mq的目录 则会报错(ROCKETMQ_HOME=D:\software\rocketmq-file\rocketmqnamesrv)
    if (null == namesrvConfig.getRocketmqHome()) {
        System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation%n", MixAll.ROCKETMQ_HOME_ENV);
        System.exit(-2);
    }
    //创建日志信息相关
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    JoranConfigurator configurator = new JoranConfigurator();
    configurator.setContext(lc);
    lc.reset();
    //日志的配置文件信息
    configurator.doConfigure(namesrvConfig.getRocketmqHome() + "/conf/logback_namesrv.xml");

    log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);

    MixAll.printObjectProperties(log, namesrvConfig);
    MixAll.printObjectProperties(log, nettyServerConfig);
    //创建真正的控制器实例
    final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);

    // remember all configs to prevent discard
    controller.getConfiguration().registerConfig(properties);

    return controller;
}

配置信息初始化完毕后,进入start流程

/**
 * 启动服务
 * @param controller
 * @return
 * @throws Exception
 */
public static NamesrvController start(final NamesrvController controller) throws Exception {

    if (null == controller) {
        throw new IllegalArgumentException("NamesrvController is null");
    }
    //执行初始化,并返回一个结果
    boolean initResult = controller.initialize();
    if (!initResult) {
        controller.shutdown();
        System.exit(-3);
    }
    //注册虚拟机关闭的钩子函数
    Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, (Callable<Void>) () -> {
        controller.shutdown();
        return null;
    }));
    //启动netty远程服务
    controller.start();

    return controller;
}

接下来就是真正启动netty远程服务的方法

public void start() throws Exception {
    //启动服务
    this.remotingServer.start();

    if (this.fileWatchService != null) {
        this.fileWatchService.start();
    }
}

RocketMQ路由注册是通过Broker与NameServer的心跳功能实现

的。Broker启动时向集群中所有的NameServer发送心跳语句,每隔30s

向集群中所有的NameServer发送心跳包,NameServer收到Broker心跳

包时会先更新brokerLiveTable缓存中BrokerLiveInfo的

lastUpdateTimestamp,然后每隔10s扫描一次brokerLiveTable,如果

连续120s没有收到心跳包,NameServer将移除该Broker的路由信息,

同时关闭Socket连接。

Broker向Namesvr发起注册,消息由DefaultRequestProcessor进行处理

@Override
public RemotingCommand processRequest(ChannelHandlerContext ctx,
    RemotingCommand request) throws RemotingCommandException {

    if (ctx != null) {
        log.debug("receive request, {} {} {}",
            request.getCode(),
            RemotingHelper.parseChannelRemoteAddr(ctx.channel()),
            request);
    }

    switch (request.getCode()) {
        case RequestCode.PUT_KV_CONFIG:
            return this.putKVConfig(ctx, request);
        case RequestCode.GET_KV_CONFIG:
            return this.getKVConfig(ctx, request);
        case RequestCode.DELETE_KV_CONFIG:
            return this.deleteKVConfig(ctx, request);
        case RequestCode.QUERY_DATA_VERSION:
            return this.queryBrokerTopicConfig(ctx, request);
            //注册broker
        case RequestCode.REGISTER_BROKER:
            return this.registerBroker(ctx, request);
        case RequestCode.UNREGISTER_BROKER:
            return this.unregisterBroker(ctx, request);
        case RequestCode.BROKER_HEARTBEAT:
            return this.brokerHeartbeat(ctx, request);
        case RequestCode.GET_BROKER_MEMBER_GROUP:
            return this.getBrokerMemberGroup(ctx, request);
        case RequestCode.GET_BROKER_CLUSTER_INFO:
            return this.getBrokerClusterInfo(ctx, request);
        case RequestCode.WIPE_WRITE_PERM_OF_BROKER:
            return this.wipeWritePermOfBroker(ctx, request);
        case RequestCode.ADD_WRITE_PERM_OF_BROKER:
            return this.addWritePermOfBroker(ctx, request);
        case RequestCode.GET_ALL_TOPIC_LIST_FROM_NAMESERVER:
            return this.getAllTopicListFromNameserver(ctx, request);
        case RequestCode.DELETE_TOPIC_IN_NAMESRV:
            return this.deleteTopicInNamesrv(ctx, request);
        case RequestCode.REGISTER_TOPIC_IN_NAMESRV:
            return this.registerTopicToNamesrv(ctx, request);
        case RequestCode.GET_KVLIST_BY_NAMESPACE:
            return this.getKVListByNamespace(ctx, request);
        case RequestCode.GET_TOPICS_BY_CLUSTER:
            return this.getTopicsByCluster(ctx, request);
        case RequestCode.GET_SYSTEM_TOPIC_LIST_FROM_NS:
            return this.getSystemTopicListFromNs(ctx, request);
        case RequestCode.GET_UNIT_TOPIC_LIST:
            return this.getUnitTopicList(ctx, request);
        case RequestCode.GET_HAS_UNIT_SUB_TOPIC_LIST:
            return this.getHasUnitSubTopicList(ctx, request);
        case RequestCode.GET_HAS_UNIT_SUB_UNUNIT_TOPIC_LIST:
            return this.getHasUnitSubUnUnitTopicList(ctx, request);
        case RequestCode.UPDATE_NAMESRV_CONFIG:
            return this.updateConfig(ctx, request);
        case RequestCode.GET_NAMESRV_CONFIG:
            return this.getConfig(ctx, request);
        case RequestCode.GET_CLIENT_CONFIG:
            return this.getClientConfigs(ctx, request);
        default:
            String error = " request type " + request.getCode() + " not supported";
            return RemotingCommand.createResponseCommand(RemotingSysResponseCode.REQUEST_CODE_NOT_SUPPORTED, error);
    }
}

RouteInfoManager实体类属性

默认主题列表

image.png

broker信息列表

image.png

集群信息列表

image.png

Broker最后注册时间表

image.png