源码分析
分析
源码从启动类开始看起
看一下在启动的过程中启动和处理了哪些事情
从主干到分支
启动类
namesrv
org.apache.rocketmq.namesrv.NamesrvStartup
broker
org.apache.rocketmq.broker.BrokerStartup
主要流程
NamesrvStartup
nameSrv主要是用于
- broker 的注册和发现
- Topic的管理 : 维护Topic与Broker 的关系
- 负载均衡 : 分发不同的broker给客户端
- 集群管理 : 监控Broker的心跳
分析main方法
读取配置
调用启动start(NamesrvController controller);
源码分析
-
initialize()中
this.kvConfigManager.load();
初始化remotingServer=new NettyRemotingServer(、remotingExecutor
调用了registerProcessor()
设置了2个定时任务
NamesrvController.this.routeInfoManager.scanNotActiveBroker();
NamesrvController.this.kvConfigManager.printAllPeriodically(); -
registerProcessor中
注册了DefaultRequestProcessor -
start()中
remotingServer.start();
设置HandshakeHandler handshakeHandler、NettyConnectManageHandler connectionManageHandler
启动NettyEventExecutor 异步读取 eventQueue
BrokerStartup
主要负责消息的收发
源码分析
- main() 中
brokerConfig = new BrokerConfig();
nettyServerConfig = new NettyServerConfig();
nettyClientConfig = new NettyClientConfig();
controller = new BrokerController
controller.initialize();
注册了异步线程池及定时处理处理:
BrokerController.this.getBrokerStats().record();
BrokerController.this.consumerOffsetManager.persist();
BrokerController.this.consumerFilterManager.persist();
BrokerController.this.protectBroker();
BrokerController.this.printWaterMark();
BrokerController.this.brokerOuterAPI.fetchNameServerAddr();
BrokerController.this.printMasterAndSlaveDiff();
然后就是加载三个功能:
initialTransaction();
initialAcl();
initialRpcHooks();
业务流程
心跳注册
入口就是BrokerController#start方法:
调用brokerOuterAPI#needRegister方法:
就是向所有nameServer发起请求(请求code为QUERY_DATA_VERSION,322),获取所有nameserver的DataVersion数据,然后一一对比自身的DataVersion数据是否一致,如果有一个nameserver的数据版本不一致则重新注册。
doRegisterBrokerAll方法的逻辑也很简单,就是向所有nameServer发起请求。
是调用另一个registerBroker方法,该方法真正的执行向一个nameserver发起注册的请求。
broker注册请求为同步请求,code为REGISTER_BROKER,103,注册的信息主要包括自身的所有topic数据、dataVersion、filterServerList、以及包括集群名、broker地址、broker名、brokerId等等在内的一些broker自身的信息。
Broker发送了心跳包之后,nameserver会进行专门的处理,保存或者更新broker上报的心跳包数据。
NameServer的默认网络处理器是DefaultRequestProcessor,因此心跳请求的入口也就是DefaultRequestProcessor#processRequest方法。
processRequest方法是一个通用的请求处理入口方法,内部会根据请求的不同requestCode进入分发处理,心跳请求的requestCode就是REGISTER_BROKER,103。
该方法用于注册broker,也就是对broker的各种路由信息进行更新或者注册。
其主要步骤为:
- 加写锁,保证线程安全。 存入或者更新brokerName信息集合clusterAddrTable。
- 存入或者更新broker基本信息集合brokerAddrTable。
- 存入一个brokerData对象。
- 如果当前broker是主broker节点。更新或者创建topic的队列配置信息集合topicQueueTable。
- 存入或者更新中broker状态信息集合brokerLiveTable。存入或者更新的信息包括最新的更新时间戳设置为当前时间,brokerLiveTable被nameServer用于执行心跳检测操作。
- 存入或者更新消费过滤信息集合filterServerList。ClassFilter模式的消费过滤集合的操作。
- 如果当前broker不是主broker节点。对返回结果result设置HaServerAddr以及MasterAddr的地址。
- 释放写锁。
scanNotActiveBroker扫描清除不活跃broker
发送消息
DefaultMQProducer#send方法作为源码分析的入口方法,该方法被使用者直接调用。
defaultMQProducerImpl中
- 同步消息send方法发送。
- 单向消息使用sendOneway发送。
- 异步消息使用带有callback函数的send方法发送。
sendDefaultImpl发送消息该方法的大概步骤为:
- 调用makeSureStateOK方法,确定此producer的服务状态正常,如果服务状态不是RUNNING,那么抛出异常。
- 调用checkMessage方法,校验消息的合法性。
- 调用tryToFindTopicPublishInfo方法,尝试查找消息的一个topic路由,用以发送消息。
- 计算循环发送消息的总次数timesTotal,默认情况下,同步模式为3,即默认允许重试2次,可更改重试次数;其他模式为1,即不允许重试,不可更改。实际上异步发送消息也会重试,最多两次,只不过不是通过这里的逻辑重试的。
- 调用selectOneMessageQueue方法,选择一个消息队列MessageQueue,该犯法支持失败故障转移。
- 调用sendKernelImpl方法发送消息,异步、同步、单向发送消息的模式都是通过该方法实现的。
- 调用updateFaultItem方法,更新本地错误表缓存数据,用于延迟时间的故障转移的功能。
- 根据发送模式执行不同的处理,如果是异步或者单向模式则直接返回,如果是同步模式,如果开启了retryAnotherBrokerWhenNotStoreOK开关,那么如果返回值不是返回SEND_OK状态,则仍然会执行重试发送。
- 此过程中,如果抛出了RemotingException、MQClientException、以及部分MQBrokerException异常时,那么会进行重试,如果抛出了InterruptedException,或者因为超时则不再重试。
selectOneMessageQueue方法用于查找一个可用的消息队列,该方法内部调用mqFaultStrategy#selectOneMessageQueue方法
接收消息
registerProcessor注册消息处理器
SendMessageProcessor这个处理器被用来专门处理发送消息请求,也就是说Producer的发送消息类请求都是通过这个处理器来处理的。这些处理器会连同对应的执行器线程池一起构建一个Pair对象,然后以requestCode为key,Pair对象为value注册到processorTable集合缓存中。
当Netty服务端接收到消息的时候,首先会在NettyServerHandler中进行处理。具体的处理器方法就是processMessageReceived方法了
文件存储
入口在:DefaultMessageStore.putMessage
- commitLog写入
- 分发ConsumeQueue和IndexFile
在DefaultMessageStore的start方法中,会启动一个后台线程reputMessageService每隔1毫秒就会去拉取CommitLog中最新更新的一批消息,然后分别转发到ComsumeQueue和IndexFile里去了恢复索引文件的方法在DefaultMappedStore#load - 文件刷盘
入口:CommitLog.submitFlushRequest - CommigLog主从复制
入口:CommitLog.submitReplicaRequest
HAService:
acceptSocketService主要负责维护Master与Slave之间的TCP连接
groupTransferService主要与主从同步复制有关
而slave相关的则是haClient - 过期文件删除
入口: DefaultMessageStore.addScheduleTask ->DefaultMessageStore.this.cleanFilesPeriodically()
延时消息
理入口在scheduleMessageService、在broker启动时也一起加载
- 消息写入
入口:CommitLog.putMessage
在CommitLog写入消息时,会判断消息的延迟级别,然后修改Message的Topic和Queue,达到转储Message的目的 - 消息转储到目标Topic
核心:scheduleMessageService
只在master节点启用、其他节点关闭
长轮询
当Broker接收到Consumer的Pull请求时,判断如果没有对应的消息,不用直接给Consumer响应(给响应也是个空的,没意义),而是就将这个Pull请求给缓存起来。当Producer发送消息过来时,增加一个步骤去检查是否有对应的已缓存的Pull请求,如果有,就及时将请求从缓存中拉取出来,并将消息通知Consumer。
consumer
org.apache.rocketmq.broker.processor.PullMessageProcessor#processRequest
如果ResponseCode.SUCCESS 则返回
如果ResponseCode.PULL_NOT_FOUND 则暂停拉取请求suspendPullRequest
加入pullRequestList
producer
org.apache.rocketmq.store.DefaultMessageStore.ReputMessageService#doReput
this.messageArrivingListener = new NotifyMessageArrivingListener(this.pullRequestHoldService);
org.apache.rocketmq.broker.longpolling.PullRequestHoldService#notifyMessageArriving中