目的:罗列希望阅读源码可以解惑的点并且搭建相关本地环境
1) 环境构建
- git 获取相关源代码,版本支持Dledger即可。
- 调整相关的配置文件设置环境变量
初次学习一切从简,不做什么额外的特性使用。我们简单从 rocketmq/distribution 盘符下 cp 出 broker.conf 至 rocketmq/conf 内。
broker.conf 默认内容不做改动,追加以下信息 。 (为了相关日志文件便于查找,我这里同步也改动了 logback_broker 、 logback_namesrv 的配置)。
#nameServer 地址 分号分割
namesrvAddr=127.0.0.1:9876
#存储路径
storePathRootDir=/Users/admin/Desktop/rocketMq/source/store
#commitLog 存储路径
storePathCommitLog=/Users/admin/Desktop/rocketMq/source/store/commitlog
消费队列存储路径
storePathConsumeQueue=/Users/admin/Desktop/rocketMq/source/store/consumequeue
消息索引|存储路径
storePathindex=/Users/admin/Desktop/rocketMq/source/store/index
#checkpoint 文件存储路径
storeCheckpoint=/Users/admin/Desktop/rocketMq/source/store/checkpoint
#abort 文件存储路径
abortFile=/Users/admin/Desktop/rocketMq/source/store/abort
- 启动 namsersrv
org.apache.rocketmq.namesrv.NamesrvStartup#main
启动项需要设置rocketMq的环境变量,如下:
ROCKETMQ_HOME = /Users/admin/Desktop/rocketMq/source/rocketmq
这里我是添加至idea环境变量中。
consule 启动输出:
- 启动 brokersrv
org.apache.rocketmq.broker.BrokerStartup#main
同样启动项需要设置rocketMq的环境变量,此外需要告知broker启动的时候加载broker.conf的盘符路径。
我这里是加在idea启动项参数中
-c /Users/admin/Desktop/rocketMq/source/rocketmq/conf/broker.conf
consule 输出如下:
broker的启动也可从之前设置log中的 breoker.log
进行查阅,简单tail 一下。
日志输出正常 , namesrv 与 broker 最简单的可供后续debug的模式算是可以了。
2) 核心类与基本流程综述
先不忙从时序角度阅读,我们先找找前人分析的文章。对rocketMq几个核心类,打下星标,形成提纲。
2.1 ) store文件相关
org.apache.rocketmq.store.MappedFile
MappedFile :00000000000000000000、00000000001073741824、00000000002147483648等文件。每个 MappedFile 统一文件大小 ,文件命名方式:fileName[n] = fileName[n - 1] + mappedFileSize,在 CommitLog 里默认为 1GB。
org.apache.rocketmq.store.MappedFileQueue
MappedFileQueue:MappedFile 所在的文件夹,对 MappedFile 进行封装成文件队列,对上层提供可无限使用的文件容量。
org.apache.rocketmq.store.CommitLog
CommitLog 目前存储在 MappedFile 有两种内容类型:
- MESSAGE :消息。
- BLANK :文件不足以存储消息时的空白占位。
org.apache.rocketmq.store.Consumequeue
上述几者关系:
RocketMQ使用MappedFile、MappedFileQueue来封装存储文件。
MappedFileQueue是MappedFile的管理容器,也是对存储目录的封装。
例如CommitLog文件的存储路径${ROCKET_HOME}/store/commitlog/,该目录下会存在多个内存映射文件(MappedFile),则会使用容器进行管理。
CommitLog : MappedFileQueue : MappedFile = 1 : 1 : N。
ConsumerQueue:MappedFileQueue : MappedFile = 1 : 1 : N。
org.apache.rocketmq.store.ReputMessageService
ConsumeQueue、IndexFile都是基于CommitLog文件构建的,当生产者提交的消息存储在Commitlog文件中时,ConsumeQueue文件需要及时更新,否则消息无法及时被消费。
RocketMQ通过开启一个线程ReputMessageServcie来实时读取CommitLog文件新增内容,使用reputFromOffset来标记已经追踪到的位置。
最终会调用到ConsumerQueue#putMessagePositionInfo
进行appendMessage
;
暂时记住有这么几个跟文件相关的类, 后再结合时序看细节。
2.2 )消息生产相关类
客户端大体流程:
生产者跟NameServer建立一个TCP长连接,然后定时从他那里拉取到最新的路由信息,包括集群里有哪些Broker,集群里有哪些Topic,每个Topic都存储在哪些Broker上。
可以根据负载均衡算法,从里面选择一台Broke机器出来,选择一台Broker(Master Broker)之后,就可以跟那个Broker也建立一个TCP长连接,然后通过长连接向Broker发送消息即可.
org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl
调用 sendDefaultImpl 进行客户端消息发送,其中关键点为
- TopicPublishInfo topicPublishInfo = this.tryToFindTopicPublishInfo(msg.getTopic());
元数据获取。 - MessageQueue mqSelected = this.selectOneMessageQueue(topicPublishInfo, astBrokerName);
获取对应路由,确认消息发送。 - sendResult = this.sendKernelImpl(msg, mq, communicationMode, sendCallback, topicPublishInfo, timeout - costTime);
进行消息发送。
服务端:
org.apache.rocketmq.store.DefaultMessageStore#asyncPutMessage
细节也同样暂时不做关注。
2.3 )消息消费者
客户端处理消息
消费者系统其实跟生产者系统原理是类似的,他们也会跟NameServer建立长连接,然后拉取路由信息,接着找到自己要获取消息的Topic在哪几台Broker上,就可以跟Broker建立长连接,从里面拉取消息了。消费者系统可能会从Master Broker拉取消息,也可能从Slave Broker拉取消息。
org.apache.rocketmq.client.impl.consumer.PullMessageService
RocketMQ使用一个单独的线程PullMessageService来负责消息的拉取。
先从pullRequestQueue中获取一个PullRequest(消息拉取任务),如果pullRequestQueue为空,则线程将阻塞,直到有拉取任务被放入。
随后调用pullMessage方法处理拿到的PullRequest进行消息拉取。
org.apache.rocketmq.client.impl.consumer.DefaultMQPushConsumerImpl
这个也是本轮的学习重点;
名字虽然是 Push 开头,实际在实现时,使用 Pull 方式实现。通过 Pull 不断不断不断轮询 Broker 获取消息。当不存在新消息时,Broker 会挂起请求,直到有新消息产生,取消挂起,返回新消息,原理类似 长轮询( Long-Polling )。
呢么目前标出来的大概有这么几个类,RocketMq里面的延时队列暂时没找到、HA与Rebalance暂时不关注, remote相关网络构建也先滞后。 确定以下对象后,开始尝试学习。