RocketMQ源码解析(五)-Broker架构及服务启动

之前几篇文章讲了Producer如何发送消息,Consumer如何收消息。后面会用更多的几篇来讲Broker,其实也就是消息队列的核心-分布式Queue的实现。
Broker的功能主要包含如下几点:

  • 接收Producer发送的消息
  • 存储消息
  • 回复consumer的消息拉取请求
  • master-slave之间的数据同步
  • 提供查询消息的接口

首先看下Broker主要的类的关系

Broker核心类

Broker核心类

数据管理类
Broker配置数据的缓存类,所有数据都以本地文件的方式存在broker上,同时会缓存全量数据在内存中。
TopicConfigManager:管理所有broker上存在的topic以及queue的信息。topic的数据会定时和nameserv做同步,以更新Nameserv上的topic路由信息。
ConsumeOffsetManager :管理每个consumer group消息消费的进度。Cluster的consumer会在消息消费成功后把offset信息同步给broker
ProducerManager:producer客户端信息
ConsumerManager:consumer客户端信息
ConsumerFilterManager:consumer filter server信息
SubscriptionGroupManager:consumer订阅信息
请求processor
客户端请求处理类,处理消息请求、配置及控制命令请求,最核心的就是SendMessageProcessor和PullMessageProcessor,一个收producer消息,一个将消息response给consumer。
SendMessageProcessor:接收Producer发来的消息,调用存储模块存储
PullMessageProcessor :接受Consumer的消息Pull请求,返回符合条件的消息
QueryMessageProcessor:接受历史消息查询请求,支持按Msg ID、Msg Key和时间段查询消息详情
AdminBrokerProcessor:接受管理命令,如topic创建等
MessageStore
消息存储接口,这个是Broker的核心,提供消息读写。
CommitLog:消息详情存储,同一个broker上的所有消息都保存在一起,每条消息保存后都会有一个offset
ConsumeQueue:按topic和queue存储消息,相同topic和queue的消息存储在一起,内容是commitLog的offset。consumer是按照queue来拉取消息的,所以都是先读取consumeQueue拿到offset的列表,然后到commitLog读取消息详情
IndexService:CommitLog的索引文件,通过对Msg Key创建索引文件,来快速的定位消息。
ReputMessageService:负责读取CommitLog文件中的消息,分发给ConsumeQueue和IndexService构建Queue和索引文件
HAService:负责消息的主从同步,对于master来说,管理所有slave并发送新的消息数据给slave
SlaveSynchronize
负责同步broker配置数据,不会同步消息数据
PullRequestHoldService
对于PushConsumer,当读取的时候没有发现消息,该类会暂时hold住请求,当有新的消息到达的时候,再回复请求。

Broker的启动过程

Broker启动主要由BrokerController完成初始化和启动的过程,下面看下具体过程BrokerController.initialize()
初始化

public boolean initialize() throws CloneNotSupportedException {
        //从持久化文件中加载数据到内存中
        boolean result = this.topicConfigManager.load();
        result = result && this.consumerOffsetManager.load();
        result = result && this.subscriptionGroupManager.load();
        result = result && this.consumerFilterManager.load();

        if (result) {
            try {
                //消息存取的核心接口初始化,提供put/get message接口,提供根据offset获取消息的接口
                this.messageStore =
                    new DefaultMessageStore(this.messageStoreConfig, this.brokerStatsManager, this.messageArrivingListener,
                        this.brokerConfig);
                //messageStore的指标统计类,提供最近一天的消息吞吐量的统计数据
                this.brokerStats = new BrokerStats((DefaultMessageStore) this.messageStore);
                //load plugin
                MessageStorePluginContext context = new MessageStorePluginContext(messageStoreConfig, brokerStatsManager, messageArrivingListener, brokerConfig);
                this.messageStore = MessageStoreFactory.build(context, this.messageStore);
                //添加消息分发器,分发到布隆过滤器
                this.messageStore.getDispatcherList().addFirst(new CommitLogDispatcherCalcBitMap(this.brokerConfig, this.consumerFilterManager));
            } catch (IOException e) {
                result = false;
                log.error("Failed to initialize", e);
            }
        }
        //message store加载内存映射文件,commit log文件,consumer queue文件,index文件
        result = result && this.messageStore.load();

        if (result) {
            //初始化netty server
            this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
            NettyServerConfig fastConfig = (NettyServerConfig) this.nettyServerConfig.clone();
            //传说中的VIP channel,端口是broker端口-2(10909),不接收consumer的Pull请求
            fastConfig.setListenPort(nettyServerConfig.getListenPort() - 2);
            this.fastRemotingServer = new NettyRemotingServer(fastConfig, this.clientHousekeepingService);
            //初始化一系列客户端命令执行的线程池
            this.sendMessageExecutor = new BrokerFixedThreadPoolExecutor(
                this.brokerConfig.getSendMessageThreadPoolNums(),
                this.brokerConfig.getSendMessageThreadPoolNums(),
                1000 * 60,
                TimeUnit.MILLISECONDS,
                this.sendThreadPoolQueue,
                new ThreadFactoryImpl("SendMessageThread_"));
            ...
            ...
            //注册消息/命令处理器,其中最重要的就是SendMessageProcessor和PullMessageProcessor,一个收producer消息一个发给consumer
            this.registerProcessor();

            //打印broker的消息吞吐信息到日志文件,每天0点记录一次
            final long initialDelay = UtilAll.computNextMorningTimeMillis() - System.currentTimeMillis();
            final long period = 1000 * 60 * 60 * 24;
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        BrokerController.this.getBrokerStats().record();
                    } catch (Throwable e) {
                        log.error("schedule record error.", e);
                    }
                }
            }, initialDelay, period, TimeUnit.MILLISECONDS);
            //记录consumerOffet到文件,默认5秒一次
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        BrokerController.this.consumerOffsetManager.persist();
                    } catch (Throwable e) {
                        log.error("schedule persist consumerOffset error.", e);
                    }
                }
            }, 1000 * 10, this.brokerConfig.getFlushConsumerOffsetInterval(), TimeUnit.MILLISECONDS);
            //记录consumer filter到文件中,10秒一次
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        BrokerController.this.consumerFilterManager.persist();
                    } catch (Throwable e) {
                        log.error("schedule persist consumer filter error.", e);
                    }
                }
            }, 1000 * 10, 1000 * 10, TimeUnit.MILLISECONDS);
            //定时检查consumer的消费记录,如果延时太大,则disable consumer,不再往这个consumer投递消息
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        BrokerController.this.protectBroker();
                    } catch (Throwable e) {
                        log.error("protectBroker error.", e);
                    }
                }
            }, 3, 3, TimeUnit.MINUTES);
            //打印当前Queue size日志
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        BrokerController.this.printWaterMark();
                    } catch (Throwable e) {
                        log.error("printWaterMark error.", e);
                    }
                }
            }, 10, 1, TimeUnit.SECONDS);
            //打印dispatch落后情况
            this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

                @Override
                public void run() {
                    try {
                        log.info("dispatch behind commit log {} bytes", BrokerController.this.getMessageStore().dispatchBehindBytes());
                    } catch (Throwable e) {
                        log.error("schedule dispatchBehindBytes error.", e);
                    }
                }
            }, 1000 * 10, 1000 * 60, TimeUnit.MILLISECONDS);
            //更新nameserv address信息
            if (this.brokerConfig.getNamesrvAddr() != null) {
                this.brokerOuterAPI.updateNameServerAddressList(this.brokerConfig.getNamesrvAddr());
                log.info("Set user specified name server address: {}", this.brokerConfig.getNamesrvAddr());
            } else if (this.brokerConfig.isFetchNamesrvAddrByAddressServer()) {
                this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            BrokerController.this.brokerOuterAPI.fetchNameServerAddr();
                        } catch (Throwable e) {
                            log.error("ScheduledTask fetchNameServerAddr exception", e);
                        }
                    }
                }, 1000 * 10, 1000 * 60 * 2, TimeUnit.MILLISECONDS);
            }
            //如果是slave,启动定时任务,每分钟从master同步配置和offset
            if (BrokerRole.SLAVE == this.messageStoreConfig.getBrokerRole()) {
                if (this.messageStoreConfig.getHaMasterAddress() != null && this.messageStoreConfig.getHaMasterAddress().length() >= 6) {
                    this.messageStore.updateHaMasterAddress(this.messageStoreConfig.getHaMasterAddress());
                    this.updateMasterHAServerAddrPeriodically = false;
                } else {
                    this.updateMasterHAServerAddrPeriodically = true;
                }

                this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            BrokerController.this.slaveSynchronize.syncAll();
                        } catch (Throwable e) {
                            log.error("ScheduledTask syncAll slave exception", e);
                        }
                    }
                }, 1000 * 10, 1000 * 60, TimeUnit.MILLISECONDS);
            } else {//如果是master,定时打印slave延时情况
                this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            BrokerController.this.printMasterAndSlaveDiff();
                        } catch (Throwable e) {
                            log.error("schedule printMasterAndSlaveDiff error.", e);
                        }
                    }
                }, 1000 * 10, 1000 * 60, TimeUnit.MILLISECONDS);
            }
            //TLS链接,监控签名文件有没有更新
            if (TlsSystemConfig.tlsMode != TlsMode.DISABLED) {
                // Register a listener to reload SslContext
               ...
               ...
            }
            //初始化事务消息service
            initialTransaction();
        }
        return result;
    }

初始化过程一共做如下几件事情:

  • 从持久化文件中加载数据,包括topic配置数据,consumer offset数据,consumer订阅配置数据和过滤配置等等
  • 初始化messageStore,MessageStore中commitLog、ConsumeQueue和index文件都是通过内存映射文件的方式来读写的。所以初始化的时候会做文件映射的初始化
  • 初始化Netty Server,Broker会同时监听两个端口,默认是10911和10909,其中10909只处理Producer的消息发送请求,所以broker上称为fastServer。客户端称之为VIP Channel
  • 注册请求的processor
  • 初始化一些定时任务,包括记录日志、consumer offset持久化、consume延迟检查、更新nameserv地址、slave的配置数据同步等
    启动
    启动的过程在BrokerController.start()方法中实现
public void start() throws Exception {
        //启动消息存储服务
        if (this.messageStore != null) {
            this.messageStore.start();
        }
        //启动netty server接收请求
        if (this.remotingServer != null) {
            this.remotingServer.start();
        }
        //启动fast netty server
        if (this.fastRemotingServer != null) {
            this.fastRemotingServer.start();
        }
        //启动tls签名文件检测服务
        if (this.fileWatchService != null) {
            this.fileWatchService.start();
        }
        //broker netty client
        if (this.brokerOuterAPI != null) {
            this.brokerOuterAPI.start();
        }
        //启动PushConsumer的请求hold服务
        if (this.pullRequestHoldService != null) {
            this.pullRequestHoldService.start();
        }
       //监控客户端连接,定时检查Producer,Consumer和Filter是否长时间未收到心跳
        if (this.clientHousekeepingService != null) {
            this.clientHousekeepingService.start();
        }
        //启动Filter Server
        if (this.filterServerManager != null) {
            this.filterServerManager.start();
        }
        //注册broker到nameserv
        this.registerBrokerAll(true, false, true);
        //周期性向nameserv发心跳,如果有变化则同步broker信息
        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(); //do nothing
        }
        //启动brokerFastFailure,定时清理长时间未执行的客户端请求
        if (this.brokerFastFailure != null) {
            this.brokerFastFailure.start();//启动超时检查
        }
        //如果是Master,开启事务消息检查
        if (BrokerRole.SLAVE != messageStoreConfig.getBrokerRole()) {
            if (this.transactionalMessageCheckService != null) {
                log.info("Start transaction service!");
                this.transactionalMessageCheckService.start();
            }
        }
    }

以上的启动过程比较简单,最重要的就是第一步中的MessageStore的启动,具体实现在DefaultMessageStore.start()中,下一篇文章我们将重点讲MessageStore数据存储的结构以及启动的过程。

你可能感兴趣的:(RocketMQ源码解析(五)-Broker架构及服务启动)