distribution/bin/mqnamesrv中启动NameServer进程的命令:
sh ${ROCKETMQ_HOME}/bin/runserver.sh org.apache.rocketmq.namesrv.NamesrvStartup $@
这行命令执行了runserver.sh,以此启动了NamesrvStartup这个Java类
JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MXX:MaxMetaspaceSize=320m"
choose_gc_options
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
JAVA_OPT="${JAVA_OPT} -Djava.ext.dirs=${JAVA_HOME}/jre/lib/ext:${BASE_DIR}/lib:${JAVA_HOME}/lib/ext"
#JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=9555,server=y,suspend=n"
JAVA_OPT="${JAVA_OPT} ${JAVA_OPT_EXT}"
JAVA_OPT="${JAVA_OPT} -cp ${CLASSPATH}"
$JAVA ${JAVA_OPT} $@
以上命令可以简化为:
java -server -Xms4g -Xmx4g -Xmn2g org.apache.rocketmq.namesrv.NamesrvStartup
这会启动一个JVM进程,执行NamesrcStartup#main()方法,完成NameServer的启动
//创建接收Broker和客户端的网络请求的组件
NamesrvController controller = createNamesrvController(args);
创建出专门用于接收Broker和客户端网络的Controller,其中有NameServer自身运行的配置和Netty的配置:
//NameServer自身运行的配置参数
final NamesrvConfig namesrvConfig = new NamesrvConfig();
//接收网络请求的Netty服务器的配置参数
final NettyServerConfig nettyServerConfig = new NettyServerConfig();
//默认监听请求的端口号:9876
nettyServerConfig.setListenPort(9876);
对于NamesrvConfig的配置:
//获取RocketMQ的环境变量的值
private String rocketmqHome = System.getProperty(MixAll.ROCKETMQ_HOME_PROPERTY, System.getenv(MixAll.ROCKETMQ_HOME_ENV));
//NameServer存放 K-V 的路径
private String kvConfigPath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "kvConfig.json";
//NameServer自己的配置存储路径
private String configStorePath = System.getProperty("user.home") + File.separator + "namesrv" + File.separator + "namesrv.properties";
//生产环境名称,默认center
private String productEnvName = "center";
//是否启动了测试集群,默认false
private boolean clusterTest = false;
//是否支持有序消息,默认false
private boolean orderMessageEnable = false;
对于NettyServerConfig的配置:
//Netty监听的端口号,外面已经设置成9876了
private int listenPort = 8888;
//Netty的工作线程数量,默认8
private int serverWorkerThreads = 8;
//Netty的public线程池的线程数量
private int serverCallbackExecutorThreads = 0;
//Netty的IO线程池中线程数,负责解析网络请求,完事交给work线程处理
private int serverSelectorThreads = 3;
//Broker在使用Netty时,会使用
private int serverOnewaySemaphoreValue = 256;
private int serverAsyncSemaphoreValue = 64;
//一个网络连接空闲超过120s,就会被关闭
private int serverChannelMaxIdleTimeSeconds = 120;
//sorket send buffer缓冲区大小
private int serverSocketSndBufSize = NettySystemConfig.socketSndbufSize;
//receive buffer缓冲区大小
private int serverSocketRcvBufSize = NettySystemConfig.socketRcvbufSize;
//ByteBuffer是否开启缓存,默认开启
private boolean serverPooledByteBufAllocatorEnable = true;
//是否开启epoll IO模型
private boolean useEpollNativeSelector = false;
现在看,Netty就是接收网络请求的,且监听的端口号是9876。一旦客户端、Broker有请求打过来,就可以处理了。
如果启动NameServer带上了配置文件地址,就基于输入流读取它、并放到那两个核心配置类中:
//如果用mqnamesrc启动时,带上了“-c”,即配置文件的地址,
//就读取配置文件的内容
if (commandLine.hasOption('c')) {
String file = commandLine.getOptionValue('c');
if (file != null) {
//基于输入流从配置文件读取配置,并放到Properties
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();
}
}
比如我配置文件nameserver.properties中有一个配置serverWorkerThreads=16,这个配置就会覆盖到核心配置类中去。
然后会把命令行中的配置读出来覆盖到NamesrvConfig、检查环境变量、打印日志等:
//如果带了“-p”,就是把NameServer的所有配置信息都打印出来
if (commandLine.hasOption('p')) {
InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
MixAll.printObjectProperties(console, namesrvConfig);
MixAll.printObjectProperties(console, nettyServerConfig);
System.exit(0);
}
//把mqnamesrv命令行中的配置,都读出来放到NamesrvConfig中去
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
//如果ROCKETMQ_HOME是空的,就输出一个异常日志
//让我们自己设置一下环境变量
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");
//打印NameServer的所有配置信息
log = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_LOGGER_NAME);
MixAll.printObjectProperties(log, namesrvConfig);
MixAll.printObjectProperties(log, nettyServerConfig);
等一切配置搞定,就构造出NamesrvController,并将NamesrcConfig、NettyServerConfig这俩核心配置交给它
//构造NamesrvController组件,并把两个核心配置类都交给它
final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);
// remember all configs to prevent discard
controller.getConfiguration().registerConfig(properties);
意图很明显了,要想启动NameServer,先初始化NamesrvConfig和NettyServerConfig这俩核心配置类,构造NamesrvController时会用得到。