RocketMQ源码解读三 Broker启动篇

Broker的启动也和NameSrv一样,主要有createBrokerController和start这2个方法

一、createBrokerController方法源码

    public static BrokerController createBrokerController(String[] args) {
        System.setProperty(RemotingCommand.REMOTING_VERSION_KEY, Integer.toString(MQVersion.CURRENT_VERSION));

        if (null == System.getProperty(NettySystemConfig.COM_ROCKETMQ_REMOTING_SOCKET_SNDBUF_SIZE)) {
            NettySystemConfig.socketSndbufSize = 131072;
        }

        if (null == System.getProperty(NettySystemConfig.COM_ROCKETMQ_REMOTING_SOCKET_RCVBUF_SIZE)) {
            NettySystemConfig.socketRcvbufSize = 131072;
        }

        try {
            Options options = ServerUtil.buildCommandlineOptions(new Options());
            commandLine = ServerUtil.parseCmdLine("mqbroker", args, buildCommandlineOptions(options),
                new PosixParser());
            if (null == commandLine) {
                System.exit(-1);
            }

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

            // 设置Netty服务端端口号是10911
            nettyServerConfig.setListenPort(10911);

            // 获取包括commitlog文件的存储路径、commitlog文件大小在内的基本信息
            final MessageStoreConfig messageStoreConfig = new MessageStoreConfig();

            // 如果当前Broker是从机,将accessMessageInMemoryMaxRatio-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);

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

            // 通过try catch来校验namesrvAddr是否满足规则
            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);
                }
            }

            switch (messageStoreConfig.getBrokerRole()) {
                case ASYNC_MASTER:
                case SYNC_MASTER:
                    brokerConfig.setBrokerId(MixAll.MASTER_ID);
                    break;
                case SLAVE:
                    if (brokerConfig.getBrokerId() <= 0) {
                        System.out.printf("Slave's brokerId must be > 0");
                        System.exit(-3);
                    }

                    break;
                default:
                    break;
            }

            if (messageStoreConfig.isEnableDLegerCommitLog()) {
                brokerConfig.setBrokerId(-1);
            }

            // 设置HA监听端口,暂不知道作用
            messageStoreConfig.setHaListenPort(nettyServerConfig.getListenPort() + 1);
            LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
            JoranConfigurator configurator = new JoranConfigurator();
            configurator.setContext(lc);
            lc.reset();
            configurator.doConfigure(brokerConfig.getRocketmqHome() + "/conf/logback_broker.xml");

            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对象,这里还会创建Topic,默认8个
            final BrokerController controller = new BrokerController(
                brokerConfig,
                nettyServerConfig,
                nettyClientConfig,
                messageStoreConfig);

            // 将命令行中设置的参数添加到对象中
            controller.getConfiguration().registerConfig(properties);

            // 见下面
            boolean initResult = controller.initialize();
            if (!initResult) {
                controller.shutdown();
                System.exit(-3);
            }

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

这里有几点要注意一下:

1)RocketMQ启动时可以通过

-c XXX.properties

命令来读取配置文件信息。properties文件如图,它主要有以下几个属性

  • brokerName:同一组broker的brokerName必须相同
  • brokerRole:有三种模式:ASYNC_MASTER、SYNC_MASTER、SLAVE。RocketMQ官网推荐,为保证数据不丢失,使用SYNC_MASTER和SLAVE模式,允许数据丢失,使用ASYNC_MASTER和SLAVE模式
  • flushDiskType:刷盘模式,有2种:ASYNC_FLUSH和SYNC_FLUSH。为了保证数据不丢失,使用SYNC_FLUSH,否则使用ASYNC_FLUSH
  • brokerId:-1:开启了dledger模式;0:SYNC_MASTER模式;>0:SLAVE模式
  • enableDLegerCommitLog:是否开启dledger模式
  • dLegerGroup:与brokerName相同
  • dLegerSelfId:节点名,必须属于dLegerPeers中的一个
  • dLegerPeers:dLegerGroup下各节点的端口信息,每个节点的配置都要一样
  • sendMessageThreadPoolNums:发送线程数
brokerClusterName=MyRaftCluster
brokerName=MyRaftBroker
brokerId=0
brokerRole=ASYNC_MASTER
flushDiskType=ASYNC_FLUSH

enableDLegerCommitLog=true
dLegerGroup=MyRaftBroker
dLegerSelfId=n0
dLegerPeers=n0-10.5.13.76:40911
sendMessageThreadPoolNums=16

2)broker客户端默认监听端口是10911,HA端口是监听端口+1,服务端端口是监听端口-2

3)在DefaultMessageStore的构造方法中,开启dLedger模式后,haService就是null,是因为haService和dLedger和冲突了吗?

二、start方法如下

这里启动了很多线程,每个线程的作用还需进一步研究 

    public void start() throws Exception {

        // 获取consumequeue文件中的最大offset,这个offset不等小于commitlog的最小offset。应该是在broker启动后,处理一些积压的数据,比较复杂
        if (this.messageStore != null) {
            this.messageStore.start();
        }

        // 创建Netty服务端,端口号10911
        if (this.remotingServer != null) {
            this.remotingServer.start();
        }

        // 创建Netty服务端,端口号10909
        if (this.fastRemotingServer != null) {
            this.fastRemotingServer.start();
        }

        // 创建守护线程,执行FileWatchService类中的start方法
        if (this.fileWatchService != null) {
            this.fileWatchService.start();
        }

        // 创建客户端
        if (this.brokerOuterAPI != null) {
            this.brokerOuterAPI.start();
        }

        // 创建守护线程,执行PullRequestHoldService类中的start方法
        if (this.pullRequestHoldService != null) {
            this.pullRequestHoldService.start();
        }

        // 监听生产者、消费者的心跳,将不活跃的连接关闭
        if (this.clientHousekeepingService != null) {
            this.clientHousekeepingService.start();
        }

        // 应该和过滤有关
        if (this.filterServerManager != null) {
            this.filterServerManager.start();
        }

        if (!messageStoreConfig.isEnableDLegerCommitLog()) {
            // 如果当前broker是master,启动守护线程类TransactionalMessageCheckService
            startProcessorByHa(messageStoreConfig.getBrokerRole());
            // 感觉像是主从同步用的
            handleSlaveSynchronize(messageStoreConfig.getBrokerRole());
            // 将Broker的ip、端口、Topic等信息注册到namesrv
            this.registerBrokerAll(true, false, true);
        }

        // 每隔30秒注册,相当于心跳
        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);

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

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


    }

三、注册broker

BrokerController类中的registerBrokerAll方法会往namesrv注册broker信息,在程序启动以及每30秒触发一次

    public synchronized void registerBrokerAll(final boolean checkOrderConfig, boolean oneway, boolean forceRegister) {

        // 获取所有Topic信息
        TopicConfigSerializeWrapper topicConfigWrapper = this.getTopicConfigManager().buildTopicConfigSerializeWrapper();

        if (!PermName.isWriteable(this.getBrokerConfig().getBrokerPermission())
            || !PermName.isReadable(this.getBrokerConfig().getBrokerPermission())) {
            ConcurrentHashMap<String, TopicConfig> topicConfigTable = new ConcurrentHashMap<String, TopicConfig>();
            for (TopicConfig topicConfig : topicConfigWrapper.getTopicConfigTable().values()) {
                TopicConfig tmp =
                    new TopicConfig(topicConfig.getTopicName(), topicConfig.getReadQueueNums(), topicConfig.getWriteQueueNums(),
                        this.brokerConfig.getBrokerPermission());
                topicConfigTable.put(topicConfig.getTopicName(), tmp);
            }
            topicConfigWrapper.setTopicConfigTable(topicConfigTable);
        }

        if (forceRegister || needRegister(this.brokerConfig.getBrokerClusterName(),
            this.getBrokerAddr(),
            this.brokerConfig.getBrokerName(),
            this.brokerConfig.getBrokerId(),
            this.brokerConfig.getRegisterBrokerTimeoutMills())) {
            doRegisterBrokerAll(checkOrderConfig, oneway, topicConfigWrapper);
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值