MappedFileQueue 代表一类文件集合,比如consumequeue/{topic}/{queueId}/目录下的所有文件
MappedFile 代表一个文件,是对这个文件操作的封装
CommitLog 代表所有的commitLog文件,里面有一个MappedFileQueue的字段
ConsumeQueue 代表了topic+queueId的所有consumeQueue文件,里面也有一个MappedFileQueue
DefaultMessageStore存储操作类
1.org.apache.rocketmq.store.DefaultMessageStore.load() 加载文件过程
org.apache.rocketmq.store.MappedFileQueue.load()中加载目录下所有文件,设置position
mappedFile.setWrotePosition(this.mappedFileSize);
mappedFile.setFlushedPosition(this.mappedFileSize);
mappedFile.setCommittedPosition(this.mappedFileSize);
这样的话假如最后一个文件没有写满,停机,再启动好像不会接着写这个文件,会重新新建一个后续文件写消息
2.org.apache.rocketmq.store.DefaultMessageStore.putMessage(MessageExtBrokerInner) 写消息过程->
this.commitLog.putMessage(msg) 拿到最后一个mappedFile文件,可能需要新建文件,使用这个文件写入 ->
org.apache.rocketmq.store.MappedFile.appendMessage(MessageExtBrokerInner, AppendMessageCallback)
如果writeBuffer不为null,会先写到writeBuffer缓存里面,后续又线程定时commit写到fileChannel里面,写消息格式
org.apache.rocketmq.store.CommitLog.DefaultAppendMessageCallback.doAppend(long, ByteBuffer, int, MessageExtBrokerInner)
写完后wrotePosition增加写的长度
3.org.apache.rocketmq.store.CommitLog.handleDiskFlush(AppendMessageResult, PutMessageResult, MessageExt) 刷盘过程
同步刷盘:
向GroupCommitService提交一个GroupCommitRequest,同时阻塞线程,等待刷盘结果
GroupCommitService的doCommit方法,在刷盘(CommitLog.this.mappedFileQueue.flush(0))结束后唤醒上面的线程,返回最终结果
异步刷盘:
唤醒FlushRealTimeService,定时调用mappedFileQueue.flush刷盘
4.consumeQueue文件的写入
org.apache.rocketmq.store.DefaultMessageStore.ReputMessageService 启动后监控commitLog文件MaxOffset有无变化,
当有变化时候
SelectMappedBufferResult result = DefaultMessageStore.this.commitLog.getData(reputFromOffset) 拿到新消息,设置新的MaxOffset
从ByteBuffer中读取消息内容,构建DispatchRequest,包含topic,topic,commitLogOffset,msgSize,tagsCode,有了这些就可以写consumeQueue文件了
DispatchRequest dispatchRequest =
DefaultMessageStore.this.commitLog.checkMessageAndReturnSize(result.getByteBuffer(), false, false);
调用DefaultMessageStore.this.doDispatch(dispatchRequest)
CommitLogDispatcherBuildConsumeQueue 写consumeQueue文件
CommitLogDispatcherBuildIndex 写index文件
5.文件结构
CommitLog
每个文件的大小默认为1G,commitlog的文件名fileName,名字长度为20位,左边补0,剩余为起始偏移量,比如 00000000000000000000 代表了第一个文件,起始偏移量为 0, 文件大小为 1G=1073741824; 当这个文件满了,第二个文件名字为 00000000001073741824
Consumequeue
消息起始物理偏移量(physical offset, long 8字节)+消息大小(int,4字节)+tagsCode(long 8字节)
每个 cosumequeue 文件的名称 fileName,名字长度为 20 位,左边补零,剩余为起始偏量; 比如 00000000000000000000 代表了第一个文件,起始偏移量为 0,文件大小为 600W, 当第一个文件满之后创建的第二个文件的名字为00000000000006000000,起始偏移量为6000000,以此类推,第三个文件名字为00000000000012000000,起始偏移量12000000。消息存储的时候会顺序写入文件,当文件满了,写入下一个文件。
6.broker读消息过程
org.apache.rocketmq.broker.processor.PullMessageProcessor.processRequest(Channel, RemotingCommand, boolean) 收到拉取消息请求
org.apache.rocketmq.store.DefaultMessageStore.getMessage(String, String, int, long, int, MessageFilter) 使用DefaultMessageStore读消息
ConsumeQueue consumeQueue = findConsumeQueue(topic, queueId) 找到对应consumeQueue
SelectMappedBufferResult bufferConsumeQueue = consumeQueue.getIndexBuffer(offset) 读取指定偏移处的ConsumeQueue内容
long offsetPy = bufferConsumeQueue.getByteBuffer().getLong();
int sizePy = bufferConsumeQueue.getByteBuffer().getInt();
long tagsCode = bufferConsumeQueue.getByteBuffer().getLong(); 得到消息偏移地址,大小,tagsCode
SelectMappedBufferResult selectResult = this.commitLog.getMessage(offsetPy, sizePy); 使用commitLog读取消息内容
MappedFile 代表一个文件,是对这个文件操作的封装
CommitLog 代表所有的commitLog文件,里面有一个MappedFileQueue的字段
ConsumeQueue 代表了topic+queueId的所有consumeQueue文件,里面也有一个MappedFileQueue
DefaultMessageStore存储操作类
private final CommitLog commitLog;
private final ConcurrentMap<String/* topic */, ConcurrentMap<Integer/* queueId */, ConsumeQueue>> consumeQueueTable;
private final FlushConsumeQueueService flushConsumeQueueService;//consumeQueue文件刷盘线程
private final CleanCommitLogService cleanCommitLogService;//定时清理commitLog线程
private final CleanConsumeQueueService cleanConsumeQueueService;//定时清理consumeQueue线程
private final IndexService indexService;//索引文件
private final AllocateMappedFileService allocateMappedFileService;
private final ReputMessageService reputMessageService;//监控commitLog文件有变化写consumeQueue
private final HAService haService;
1.org.apache.rocketmq.store.DefaultMessageStore.load() 加载文件过程
org.apache.rocketmq.store.MappedFileQueue.load()中加载目录下所有文件,设置position
mappedFile.setWrotePosition(this.mappedFileSize);
mappedFile.setFlushedPosition(this.mappedFileSize);
mappedFile.setCommittedPosition(this.mappedFileSize);
这样的话假如最后一个文件没有写满,停机,再启动好像不会接着写这个文件,会重新新建一个后续文件写消息
2.org.apache.rocketmq.store.DefaultMessageStore.putMessage(MessageExtBrokerInner) 写消息过程->
this.commitLog.putMessage(msg) 拿到最后一个mappedFile文件,可能需要新建文件,使用这个文件写入 ->
org.apache.rocketmq.store.MappedFile.appendMessage(MessageExtBrokerInner, AppendMessageCallback)
如果writeBuffer不为null,会先写到writeBuffer缓存里面,后续又线程定时commit写到fileChannel里面,写消息格式
org.apache.rocketmq.store.CommitLog.DefaultAppendMessageCallback.doAppend(long, ByteBuffer, int, MessageExtBrokerInner)
写完后wrotePosition增加写的长度
3.org.apache.rocketmq.store.CommitLog.handleDiskFlush(AppendMessageResult, PutMessageResult, MessageExt) 刷盘过程
同步刷盘:
向GroupCommitService提交一个GroupCommitRequest,同时阻塞线程,等待刷盘结果
GroupCommitService的doCommit方法,在刷盘(CommitLog.this.mappedFileQueue.flush(0))结束后唤醒上面的线程,返回最终结果
异步刷盘:
唤醒FlushRealTimeService,定时调用mappedFileQueue.flush刷盘
4.consumeQueue文件的写入
org.apache.rocketmq.store.DefaultMessageStore.ReputMessageService 启动后监控commitLog文件MaxOffset有无变化,
当有变化时候
SelectMappedBufferResult result = DefaultMessageStore.this.commitLog.getData(reputFromOffset) 拿到新消息,设置新的MaxOffset
从ByteBuffer中读取消息内容,构建DispatchRequest,包含topic,topic,commitLogOffset,msgSize,tagsCode,有了这些就可以写consumeQueue文件了
DispatchRequest dispatchRequest =
DefaultMessageStore.this.commitLog.checkMessageAndReturnSize(result.getByteBuffer(), false, false);
调用DefaultMessageStore.this.doDispatch(dispatchRequest)
CommitLogDispatcherBuildConsumeQueue 写consumeQueue文件
CommitLogDispatcherBuildIndex 写index文件
5.文件结构
CommitLog
每个文件的大小默认为1G,commitlog的文件名fileName,名字长度为20位,左边补0,剩余为起始偏移量,比如 00000000000000000000 代表了第一个文件,起始偏移量为 0, 文件大小为 1G=1073741824; 当这个文件满了,第二个文件名字为 00000000001073741824
Consumequeue
消息起始物理偏移量(physical offset, long 8字节)+消息大小(int,4字节)+tagsCode(long 8字节)
每个 cosumequeue 文件的名称 fileName,名字长度为 20 位,左边补零,剩余为起始偏量; 比如 00000000000000000000 代表了第一个文件,起始偏移量为 0,文件大小为 600W, 当第一个文件满之后创建的第二个文件的名字为00000000000006000000,起始偏移量为6000000,以此类推,第三个文件名字为00000000000012000000,起始偏移量12000000。消息存储的时候会顺序写入文件,当文件满了,写入下一个文件。
6.broker读消息过程
org.apache.rocketmq.broker.processor.PullMessageProcessor.processRequest(Channel, RemotingCommand, boolean) 收到拉取消息请求
org.apache.rocketmq.store.DefaultMessageStore.getMessage(String, String, int, long, int, MessageFilter) 使用DefaultMessageStore读消息
ConsumeQueue consumeQueue = findConsumeQueue(topic, queueId) 找到对应consumeQueue
SelectMappedBufferResult bufferConsumeQueue = consumeQueue.getIndexBuffer(offset) 读取指定偏移处的ConsumeQueue内容
long offsetPy = bufferConsumeQueue.getByteBuffer().getLong();
int sizePy = bufferConsumeQueue.getByteBuffer().getInt();
long tagsCode = bufferConsumeQueue.getByteBuffer().getLong(); 得到消息偏移地址,大小,tagsCode
SelectMappedBufferResult selectResult = this.commitLog.getMessage(offsetPy, sizePy); 使用commitLog读取消息内容