RocketMQ在启动 Namesrv 的过程中会创建NamesrvController控制器,并初始化一些核心组件RouteInfoManager路由信息管理组件、NettyRemotingServer网络通信服务器组件、BrokerHousekeepingService网络通信监听器组件,使用了大量JUC并发知识和Netty网络通信的应用。
它启动后,主要负责与Broker通信维护消息队列路由信息,且与Producer/Consumer通信分发路由信息。
源码版本:4.9.3
RocketMQ入门请查阅我的另一篇笔记 RocketMQ入门与最佳实践-CSDN博客
源码入口 org.apache.rocketmq.namesrv.NamesrvStartup#main
主流程如下,很简洁,先创建核心的NamesrvController控制器,再启动控制器。
public static NamesrvController main0(String[] args) {
try {
// 创建NameServer控制器
NamesrvController controller = createNamesrvController(args);
// 启动NameServer控制器
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;
}
下面深入看下每一步实现:
创建Namesrv控制器阶段:先解析并处理的命令行参数,有处理的设计的日志配置,并且将配置参数加载到Namesrv配置,最后创建了非常关键的
public static NamesrvController createNamesrvController(String[] args) throws IOException, JoranException {
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;
}
// 创建NameServer配置、NettyServer配置,并初始化nettyServerConfig监听端口为9876
final NamesrvConfig namesrvConfig = new NamesrvConfig();
final NettyServerConfig nettyServerConfig = new NettyServerConfig();
nettyServerConfig.setListenPort(9876);
if (commandLine.hasOption('c')) {
// 包含命令行参数-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')) {
// 包含命令行参数-p,打印命令行参数,并退出程序
InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.NAMESRV_CONSOLE_NAME);
MixAll.printObjectProperties(console, namesrvConfig);
MixAll.printObjectProperties(console, nettyServerConfig);
System.exit(0);
}
// 将命令行配置参数设置到NameServer配置中
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), namesrvConfig);
// 必须设置rocketmqHome
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);
// 创建NameServer控制器
final NamesrvController controller = new NamesrvController(namesrvConfig, nettyServerConfig);
// remember all configs to prevent discard
// 将命令行参数设置到NameServer配置中
controller.getConfiguration().registerConfig(properties);
return controller;
}
先对控制器进行初始化操作(具体怎么初始化和启动,后续一步一步点进去分析),又对当前应用所在的JVM注册了一个钩子函数,在JVM关闭时,进行回调,用于清理控制器所占用的系统资源。最后,启动了控制器。
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);
}
// 注册JVM关闭钩子
Runtime.getRuntime().addShutdownHook(new ShutdownHookThread(log, new Callable() {
@Override
public Void call() throws Exception {
// JVM关闭是,关闭控制器
controller.shutdown();
return null;
}
}));
// 启动控制器
controller.start();
return controller;
}
跟进去看下控制器初始化都干了什么事情:
public boolean initialize() {
// 从磁盘文件加载历史KV配置
this.kvConfigManager.load();
// 启动网络通信服务器
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.brokerHousekeepingService);
// 启动异步执行的工作线程池,8个线程
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配置打印线程,定时打印所有KV配置
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
NamesrvController.this.kvConfigManager.printAllPeriodically();
}
}, 1, 10, TimeUnit.MINUTES);
// 启动TLS服务
if (TlsSystemConfig.tlsMode != TlsMode.DISABLED) {
// Register a listener to reload SslContext
try {
// 初始化文件监听服务,监听本地指定磁盘目录的TLS证书文件变化
fileWatchService = new FileWatchService(
// 监听的TLS证书文件目录
new String[] {
TlsSystemConfig.tlsServerCertPath,
TlsSystemConfig.tlsServerKeyPath,
TlsSystemConfig.tlsServerTrustCertPath
},
// 监听回调
new FileWatchService.Listener() {
boolean certChanged, keyChanged = false;
@Override
public void onChanged(String path) {
// 监听到TLS证书文件变化,重新加载SSL上下文
if (path.equals(TlsSystemConfig.tlsServerTrustCertPath)) {
log.info("The trust certificate changed, reload the ssl context");
reloadServerSslContext();
}
if (path.equals(TlsSystemConfig.tlsServerCertPath)) {
certChanged = true;
}
if (path.equals(TlsSystemConfig.tlsServerKeyPath)) {
keyChanged = true;
}
if (certChanged && keyChanged) {
log.info("The certificate and private key changed, reload the ssl context");
certChanged = keyChanged = false;
reloadServerSslContext();
}
}
private void reloadServerSslContext() {
((NettyRemotingServer) remotingServer).loadSslContext();
}
});
} catch (Exception e) {
log.warn("FileWatchService created error, can't load the certificate dynamically");
}
}
return true;
}
public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
final ChannelEventListener channelEventListener) {
// 两种RPC请求方式,对应的信号量阈值,用于发送RPC请求时,进行并发控制,保护系统内存
super(nettyServerConfig.getServerOnewaySemaphoreValue(), nettyServerConfig.getServerAsyncSemaphoreValue());
// netty提供的启动netty网络服务器的启动脚本
this.serverBootstrap = new ServerBootstrap();
// netty服务器配置
this.nettyServerConfig = nettyServerConfig;
// 监听netty服务器事件的监听器
this.channelEventListener = channelEventListener;
int publicThreadNums = nettyServerConfig.getServerCallbackExecutorThreads();
if (publicThreadNums <= 0) {
publicThreadNums = 4;
}
// 公共线程池初始化,默认4个线程,用于执行服务器回调逻辑
this.publicExecutor = Executors.newFixedThreadPool(publicThreadNums, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "NettyServerPublicExecutor_" + this.threadIndex.incrementAndGet());
}
});
if (useEpoll()) {
this.eventLoopGroupBoss = new EpollEventLoopGroup(1, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyEPOLLBoss_%d", this.threadIndex.incrementAndGet()));
}
});
this.eventLoopGroupSelector = new EpollEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
private int threadTotal = nettyServerConfig.getServerSelectorThreads();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyServerEPOLLSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
}
});
} else {
// 非epoll模式
// 初始化建立连接的线程池,默认1个线程
this.eventLoopGroupBoss = new NioEventLoopGroup(1, new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyNIOBoss_%d", this.threadIndex.incrementAndGet()));
}
});
// 初始化处理请求的线程池,默认3个线程
this.eventLoopGroupSelector = new NioEventLoopGroup(nettyServerConfig.getServerSelectorThreads(), new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
private int threadTotal = nettyServerConfig.getServerSelectorThreads();
@Override
public Thread newThread(Runnable r) {
return new Thread(r, String.format("NettyServerNIOSelector_%d_%d", threadTotal, this.threadIndex.incrementAndGet()));
}
});
}
// 加载ssl上下文,安全相关
loadSslContext();
}
接下来看控制器start()启动都干了什么事:先启动网络通信服务器,又启动了监听TLS密钥文件的文件监听服务。
public void start() throws Exception {
// 启动网络通信服务器
this.remotingServer.start();
if (this.fileWatchService != null) {
// 启动文件监听服务
this.fileWatchService.start();
}
}
先启动了网络通信服务器:
public void start() {
// 默认网络事件执行池初始化,默认8个线程
this.defaultEventExecutorGroup = new DefaultEventExecutorGroup(
nettyServerConfig.getServerWorkerThreads(),
new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "NettyServerCodecThread_" + this.threadIndex.incrementAndGet());
}
});
// 预处理握手用的handler
prepareSharableHandlers();
// 真正的创建一个netty server
ServerBootstrap childHandler =
this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupSelector)
.channel(useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, nettyServerConfig.getServerSocketBacklog()) // tcp3次握手队列长度
.option(ChannelOption.SO_REUSEADDR, true) //
.option(ChannelOption.SO_KEEPALIVE, false) // 是否自动发送探测包,探测网络连接是否存活
.childOption(ChannelOption.TCP_NODELAY, true) // 禁止打包传输,避免网络延迟
.localAddress(new InetSocketAddress(this.nettyServerConfig.getListenPort()))
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline()
// 3次握手处理handler
.addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, handshakeHandler)
.addLast(defaultEventExecutorGroup,
encoder, // 编码器
new NettyDecoder(), // 解码器
// 空闲检测handler
new IdleStateHandler(0, 0, nettyServerConfig.getServerChannelMaxIdleTimeSeconds()),
connectionManageHandler, // 连接管理handler
serverHandler // 服务器handler
);
}
});
// 网络服务器收发消息缓存大小
if (nettyServerConfig.getServerSocketSndBufSize() > 0) {
log.info("server set SO_SNDBUF to {}", nettyServerConfig.getServerSocketSndBufSize());
childHandler.childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSndBufSize());
}
if (nettyServerConfig.getServerSocketRcvBufSize() > 0) {
log.info("server set SO_RCVBUF to {}", nettyServerConfig.getServerSocketRcvBufSize());
childHandler.childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketRcvBufSize());
}
// 设置写缓冲区水位
if (nettyServerConfig.getWriteBufferLowWaterMark() > 0 && nettyServerConfig.getWriteBufferHighWaterMark() > 0) {
log.info("server set netty WRITE_BUFFER_WATER_MARK to {},{}",
nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark());
childHandler.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(
nettyServerConfig.getWriteBufferLowWaterMark(), nettyServerConfig.getWriteBufferHighWaterMark()));
}
// 是否开启内存池分配机制
if (nettyServerConfig.isServerPooledByteBufAllocatorEnable()) {
childHandler.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
}
try {
// 绑定端口,同步获取长连接通道
ChannelFuture sync = this.serverBootstrap.bind().sync();
InetSocketAddress addr = (InetSocketAddress) sync.channel().localAddress();
this.port = addr.getPort();
} catch (InterruptedException e1) {
throw new RuntimeException("this.serverBootstrap.bind().sync() InterruptedException", e1);
}
if (this.channelEventListener != null) {
// 启动网络异常事件监听器
this.nettyEventExecutor.start();
}
// 启动扫描超时请求任务
this.timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
NettyRemotingServer.this.scanResponseTable();
} catch (Throwable e) {
log.error("scanResponseTable exception", e);
}
}
}, 1000 * 3, 1000);
}
然后启动了文件监听服务:
public void start() {
log.info("Try to start service thread:{} started:{} lastThread:{}", getServiceName(), started.get(), thread);
// CAS方式进行并发控制,避免重复启动
if (!started.compareAndSet(false, true)) {
return;
}
// 初始化停止标志
stopped = false;
// 启动线程,run函数实现在子类中
this.thread = new Thread(this, getServiceName());
this.thread.setDaemon(isDaemon);
this.thread.start();
}
最后看看如何关闭NamesrvController:
public void shutdown() {
// 关闭网络服务器
this.remotingServer.shutdown();
// 关闭网络服务器执行线程池
this.remotingExecutor.shutdown();
// 关闭定时调度任务线程池
this.scheduledExecutorService.shutdown();
// 关闭文件监听服务
if (this.fileWatchService != null) {
this.fileWatchService.shutdown();
}
}
this.remotingServer.shutdown()的具体关闭逻辑:
public void shutdown() {
try {
// 关闭定时器
if (this.timer != null) {
this.timer.cancel();
}
// 关闭物理网络连接管理器
this.eventLoopGroupBoss.shutdownGracefully();
// 关闭数据传输网络连接管理器
this.eventLoopGroupSelector.shutdownGracefully();
// 关闭网络异常事件监听器
if (this.nettyEventExecutor != null) {
this.nettyEventExecutor.shutdown();
}
// 关闭默认线程池
if (this.defaultEventExecutorGroup != null) {
this.defaultEventExecutorGroup.shutdownGracefully();
}
} catch (Exception e) {
log.error("NettyRemotingServer shutdown exception, ", e);
}
if (this.publicExecutor != null) {
try {
this.publicExecutor.shutdown();
} catch (Exception e) {
log.error("NettyRemotingServer shutdown exception, ", e);
}
}
}