前言
RocketMQ在启动Broker过程会创建BorkerContoller控制器,初始化大量配置、核心组件、启动大量后台线程。从部署架构中可以看出它主要负责与Namesrv建立netty长连接,上报Routing Info路由信息,也与Producer Cluster和Consumer Cluster建立netty长连接,发送、接收消息。
源码版本:4.9.3
rocketmq部署架构
源码分析
源码入口
broker模块下的 org.apache.rocketmq.broker.BrokerStartup#main
主流程
今天看主流程,它的源码特别清晰,先创建BorkerController控制器对象,在启动控制器,就可以了。那么我们下面,深入一层细看一下怎么创建和怎么启动的?
public static void main(String[] args) {
// 创建BrokerController控制器,且启动
start(createBrokerController(args));
}
public static BrokerController start(BrokerController controller) {
try {
// 启动broker控制器
controller.start();
String tip = "The broker[" + controller.getBrokerConfig().getBrokerName() + ", "
+ controller.getBrokerAddr() + "] boot success. serializeType=" + RemotingCommand.getSerializeTypeConfigInThisServer();
if (null != controller.getBrokerConfig().getNamesrvAddr()) {
tip += " and name server is " + controller.getBrokerConfig().getNamesrvAddr();
}
log.info(tip);
System.out.printf("%s%n", tip);
return controller;
} catch (Throwable e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
创建Borker控制器流程
- 设置系统属性,rocketmq版本;
- 解析命令行参数到命令行对象;
- 初始化核心配置,borker配置、nettyServer配置、nettyClient配置;
- 初始消息存储配置,如果是slave从节点,则减少内存最大占用10%,默认主节点(异步复制)不做内存占用优化;
- 如果命令号参数中有-c参数,则从指定磁盘文件中加载配置文件;
- 对环境变量和namsrv进行解析校验;
- 设置brokerId,默认角色ASYNC_MASTER(主节点且异步复制)设置为0,从节点设置为必须大于0;
- 如果是Dleger 高可用模式,则将brokerId设置为 -1,因为该模式下,会自动进行选主操作,后边会安排单独的笔记分享;
- 设置监听的高可用端口;
- 初始化日志组件;
- 处理命令行参数,如果包含 -p,则在控制台打印配置信息,并退出程序;
- 如果包含命令行参数,则在控制台 仅仅打印重要的配置信息,并退出程序;
- 打印配置信息到日志文件;
- 【重要】创建BrokerController控制器实例;
- 初始化BrokerController控制器实例;
- 注册JVM钩子,在JVM关闭时执行钩子回调,进行BrokerController控制器实例关闭处理;
public static BrokerController createBrokerController(String[] args) {
// 设置系统属性,rocketmq版本
System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));
try {
//PackageConflictDetect.detectFastjson();
// 创建了一个命令行配置项
Options options = ServerUtil.buildCommandlineOptions(new Options());
// 解析启动参数到命令行
commandLine = ServerUtil.parseCmdLine("mqbroker", args, buildCommandlineOptions(options),
new PosixParser());
if (null == commandLine) {
System.exit(-1);
}
// 配置初始化,broker配置,nettyServer配置,nettyClient配置
final BrokerConfig brokerConfig = new BrokerConfig();
final NettyServerConfig nettyServerConfig = new NettyServerConfig();
final NettyClientConfig nettyClientConfig = new NettyClientConfig();
nettyClientConfig.setUseTLS(Boolean.parseBoolean(System.getProperty(TLS_ENABLE,
String.valueOf(TlsSystemConfig.tlsMode == TlsMode.ENFORCING))));
// broker作为server服务端的监听的端口号
nettyServerConfig.setListenPort(10911);
// 存储配置,
final MessageStoreConfig messageStoreConfig = new MessageStoreConfig();
// 如果是slave,则减少内存占用 10%,默认主节点(异步复制)不做内存占用优化
if (BrokerRole.SLAVE == messageStoreConfig.getBrokerRole()) {
int ratio = messageStoreConfig.getAccessMessageInMemoryMaxRatio() - 10;
messageStoreConfig.setAccessMessageInMemoryMaxRatio(ratio);
}
// 如果命令行参数中有-c参数,则加载配置文件
if (commandLine.hasOption('c')) {
String file = commandLine.getOptionValue('c');
if (file != null) {
configFile = file;
InputStream in = new BufferedInputStream(new FileInputStream(file));
properties = new Properties();
properties.load(in);
properties2SystemEnv(properties);
MixAll.properties2Object(properties, brokerConfig);
MixAll.properties2Object(properties, nettyServerConfig);
MixAll.properties2Object(properties, nettyClientConfig);
MixAll.properties2Object(properties, messageStoreConfig);
BrokerPathConfigHelper.setBrokerConfigPath(file);
in.close();
}
}
MixAll.properties2Object(ServerUtil.commandLine2Properties(commandLine), brokerConfig);
// 必须配置在环境中配置 ROCKETMQ_HOME 地址
if (null == brokerConfig.getRocketmqHome()) {
System.out.printf("Please set the %s variable in your environment to match the location of the RocketMQ installation", MixAll.ROCKETMQ_HOME_ENV);
System.exit(-2);
}
// 对集群化部署的namesrv地址进行解析校验
String namesrvAddr = brokerConfig.getNamesrvAddr();
if (null != namesrvAddr) {
try {
String[] addrArray = namesrvAddr.split(";");
for (String addr : addrArray) {
RemotingUtil.string2SocketAddress(addr);
}
} catch (Exception e) {
System.out.printf(
"The Name Server Address[%s] illegal, please set it as follows, \"127.0.0.1:9876;192.168.0.1:9876\"%n",
namesrvAddr);
System.exit(-3);
}
}
// 设置brokerId,默认角色为ASYNC_MASTER(主节点 异步复制)
switch (messageStoreConfig.getBrokerRole()) {
// 主节点,必须设置为 0
case ASYNC_MASTER:
case SYNC_MASTER:
brokerConfig.setBrokerId(MixAll.MASTER_ID);
break;
// 从节点,brokerId必须大于0
case SLAVE:
if (brokerConfig.getBrokerId() <= 0) {
System.out.printf("Slave's brokerId must be > 0");
System.exit(-3);
}
break;
default:
break;
}
// 如果是分布式集群(HA高可用模式),则brokerId必须为-1
if (messageStoreConfig.isEnableDLegerCommitLog()) {
brokerConfig.setBrokerId(-1);
}
// 设置ha ListenPort 比系统端口号大1,避免与系统端口冲突
messageStoreConfig.setHaListenPort(nettyServerConfig.getListenPort() + 1);
// 初始化日志组件
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(lc);
lc.reset();
System.setProperty("brokerLogDir", "");
if (brokerConfig.isIsolateLogEnable()) {
System.setProperty("brokerLogDir", brokerConfig.getBrokerName() + "_" + brokerConfig.getBrokerId());
}
if (brokerConfig.isIsolateLogEnable() && messageStoreConfig.isEnableDLegerCommitLog()) {
System.setProperty("brokerLogDir", brokerConfig.getBrokerName() + "_" + messageStoreConfig.getdLegerSelfId());
}
configurator.doConfigure(brokerConfig.getRocketmqHome() + "/conf/logback_broker.xml");
// 如果包含参数 -p,则在控制台打印配置信息,并退出
if (commandLine.hasOption('p')) {
InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.BROKER_CONSOLE_NAME);
MixAll.printObjectProperties(console, brokerConfig);
MixAll.printObjectProperties(console, nettyServerConfig);
MixAll.printObjectProperties(console, nettyClientConfig);
MixAll.printObjectProperties(console, messageStoreConfig);
System.exit(0);
} else if (commandLine.hasOption('m')) {
// 在控制台仅仅打印重要配置信息
InternalLogger console = InternalLoggerFactory.getLogger(LoggerName.BROKER_CONSOLE_NAME);
MixAll.printObjectProperties(console, brokerConfig, true);
MixAll.printObjectProperties(console, nettyServerConfig, true);
MixAll.printObjectProperties(console, nettyClientConfig, true);
MixAll.printObjectProperties(console, messageStoreConfig, true);
System.exit(0);
}
// 打印配置信息到日志文件
log = InternalLoggerFactory.getLogger(LoggerName.BROKER_LOGGER_NAME);
MixAll.printObjectProperties(log, brokerConfig);
MixAll.printObjectProperties(log, nettyServerConfig);
MixAll.printObjectProperties(log, nettyClientConfig);
MixAll.printObjectProperties(log, messageStoreConfig);
// 创建BrokerController实例
final BrokerController controller = new BrokerController(
brokerConfig,
nettyServerConfig,
nettyClientConfig,
messageStoreConfig);
// remember all configs to prevent discard
controller.getConfiguration().registerConfig(properties);
// 初始化BrokerController控制器
boolean initResult = controller.initialize();
if (!initResult) {
// 初始化失败,自动关闭,然后退出程序
controller.shutdown();
System.exit(-3);
}
// 注册JVM钩子,在JVM关闭时执行关闭操作
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
private volatile boolean hasShutdown = false;
private AtomicInteger shutdownTimes = new AtomicInteger(0);
@Override
public void run() {
synchronized (this) {
log.info("Shutdown hook was invoked, {}", this.shutdownTimes.incrementAndGet());
if (!this.hasShutdown) {
this.hasShutdown = true;
long beginTime = System.currentTimeMillis();
// 关闭控制器
controller.shutdown();
long consumingTimeTotal = System.currentTimeMillis() - beginTime;
log.info("Shutdown hook over, consuming total time(ms): {}", consumingTimeTotal);
}
}
}
}, "ShutdownHook"));
return controller;
} catch (Throwable e) {
e.printStackTrace();
System.exit(-1);
}
return null;
}
启动Broker控制器流程
启动控制流程涉及的组件非常多,跟broker本身的复杂度有关系,详细的流程已经体现在下面的代码注释中。
public void start() throws Exception {
// 启动消息存储组件
if (this.messageStore != null) {
this.messageStore.start();
}
// 启动RemotingServer网络通信服务器
if (this.remotingServer != null) {
this.remotingServer.start();
}
if (this.fastRemotingServer != null) {
this.fastRemotingServer.start();
}
// 启动文件监听服务(监控本地磁盘文件中配置TLS安全加密文件的变更)
if (this.fileWatchService != null) {
this.fileWatchService.start();
}
// 启动broker对外API服务
if (this.brokerOuterAPI != null) {
this.brokerOuterAPI.start();
}
// 启动Pull请求方式服务
if (this.pullRequestHoldService != null) {
this.pullRequestHoldService.start();
}
// 启动客户端HouseKeeping服务(长连接变更监听器)
if (this.clientHousekeepingService != null) {
this.clientHousekeepingService.start();
}
// 启动filter服务
if (this.filterServerManager != null) {
this.filterServerManager.start();
}
// 启动broker主从同步服务
if (!messageStoreConfig.isEnableDLegerCommitLog()) {
startProcessorByHa(messageStoreConfig.getBrokerRole());
handleSlaveSynchronize(messageStoreConfig.getBrokerRole());
this.registerBrokerAll(true, false, true);
}
// 注册一个定时任务,每隔10秒注册Broker信息到NameServer(心跳)
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
BrokerController.this.registerBrokerAll(true, false, brokerConfig.isForceRegister());
} catch (Throwable e) {
log.error("registerBrokerAll Exception", e);
}
}
}, 1000 * 10, Math.max(10000, Math.min(brokerConfig.getRegisterNameServerPeriod(), 60000)), TimeUnit.MILLISECONDS);
// 启动Broker统计信息服务
if (this.brokerStatsManager != null) {
this.brokerStatsManager.start();
}
//
if (this.brokerFastFailure != null) {
this.brokerFastFailure.start();
}
}
关闭Broker控制器流程
整体流程很清晰,就如关闭大量的服务组件和后台线程池,如下:
public void shutdown() {
// 关闭broker统计信息服务
if (this.brokerStatsManager != null) {
this.brokerStatsManager.shutdown();
}
// 关闭网络连接监听服务
if (this.clientHousekeepingService != null) {
this.clientHousekeepingService.shutdown();
}
// 关闭拉取请求服务
if (this.pullRequestHoldService != null) {
this.pullRequestHoldService.shutdown();
}
// 关闭网络通信服务器
if (this.remotingServer != null) {
this.remotingServer.shutdown();
}
// 关闭网络通信服务器
if (this.fastRemotingServer != null) {
this.fastRemotingServer.shutdown();
}
// 关闭文件监听服务
if (this.fileWatchService != null) {
this.fileWatchService.shutdown();
}
// 关闭消息存储服务
if (this.messageStore != null) {
this.messageStore.shutdown();
}
// 关闭定时任务服务
this.scheduledExecutorService.shutdown();
try {
this.scheduledExecutorService.awaitTermination(5000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
}
// 删除namesrv注册的broker信息
this.unregisterBrokerAll();
// 关闭发送消息线程池
if (this.sendMessageExecutor != null) {
this.sendMessageExecutor.shutdown();
}
// 关闭接受消息Future线程池
if (this.putMessageFutureExecutor != null) {
this.putMessageFutureExecutor.shutdown();
}
// 关闭拉取消息线程池
if (this.pullMessageExecutor != null) {
this.pullMessageExecutor.shutdown();
}
// 关闭回查消息线程池
if (this.replyMessageExecutor != null) {
this.replyMessageExecutor.shutdown();
}
// 关闭后台管理服务线程池
if (this.adminBrokerExecutor != null) {
this.adminBrokerExecutor.shutdown();
}
// 关闭外部接口服务
if (this.brokerOuterAPI != null) {
this.brokerOuterAPI.shutdown();
}
// 持久化消费进度
this.consumerOffsetManager.persist();
// 关闭过滤器服务
if (this.filterServerManager != null) {
this.filterServerManager.shutdown();
}
// 关闭快速失败服务
if (this.brokerFastFailure != null) {
this.brokerFastFailure.shutdown();
}
// 持久化filter消费进度
if (this.consumerFilterManager != null) {
this.consumerFilterManager.persist();
}
// 关闭客户端管理服务
if (this.clientManageExecutor != null) {
this.clientManageExecutor.shutdown();
}
// 关闭查询消息线程池
if (this.queryMessageExecutor != null) {
this.queryMessageExecutor.shutdown();
}
// 关闭消费管理线程池
if (this.consumerManageExecutor != null) {
this.consumerManageExecutor.shutdown();
}
// 关闭文件监听服务
if (this.fileWatchService != null) {
this.fileWatchService.shutdown();
}
// 关闭事务消息检查服务
if (this.transactionalMessageCheckService != null) {
this.transactionalMessageCheckService.shutdown(false);
}
// 关闭事务消息结束服务
if (this.endTransactionExecutor != null) {
this.endTransactionExecutor.shutdown();
}
}