简介
每个ConsumeQueue都有一个id,id 的值为0到TopicConfig配置的队列数量。比如某个Topic的消费队列数量为4,那么四个ConsumeQueue的id就分别为0、1、2、3。
ConsumeQueue是不负责存储消息的,只是负责记录它所属Topic的消息在CommitLog中的偏移量,这样当消费者从Broker拉取消息的时候,就可以快速根据偏移量定位到消息。
ConsumeQueue本身同样是利用MappedFileQueue进行记录偏移量信息的,可见MappedFileQueue的设计多么美妙,它没有与消息进行耦合,而是设计成一个通用的存储功能。
ReputMessageService服务
每个Broker在初始化的时候都会初始化一个MessageStore负责存储消息,而MessageStore在初始化的时候,同样会启动一个ReputMessageService,ReputMessageService就是用来更新ConsumeQueue中消息偏移的。
也就是说,MessageStore与ConsumeQueue之间维持一个长连接,消息内容存MessageStore,而消息偏移(可以理解为消息索引)存ConsumeQueue,这两者之间是保持一致的。
ReputMessageService本身是一个线程,它启动后便会在循环中不断调用doReput()方法,用来通知ConsumeQueue进行更新。
@Override
public void run() {
while (!this.isStopped()) {
try {
Thread.sleep(1);
this.doReput();
} catch (Exception e) {
DefaultMessageStore.log.warn(this.getServiceName() + " service has exception. ", e);
}
}
}
doReput()中主要分为以下几步:
1:获取CommitLog中存储的新消息。
SelectMappedBufferResult result = DefaultMessageStore.this.commitLog.getData(reputFromOffset);
2:如果第一步获取的消息不为空,则表明有新消息被存储到CommitLog中,此时便会通知ConsumeQueue更新消息偏移
// dispatch 意思是 派遣调度分发发出
DispatchRequest dispatchRequest =
DefaultMessageStore.this.commitLog.checkMessageAndReturnSize(result.getByteBuffer(), false, false);
......
DefaultMessageStore.this.doDispatch(dispatchRequest);
3:更新reputFromOffset,设置为下次需要拉取的消息在CommitLog中的偏移。
this.reputFromOffset = result.getStartOffset();
......
int size = dispatchRequest.getMsgSize();
......
this.reputFromOffset += size;
上面的重点在第二步中,这里调用 DefaultMessageStore.this.doDispatch(dispatchRequest) 来通知ConsumeQueue。
DefaultMessageStore中存储了一个dispatcherList,其中存放了几个CommitLogDispatcher对象,它们都是用来监听CommitLog中新消息存储的