一、概述
上篇分析了DefaultMessageStore的大体功能和DefaultMessageStore生命周期的关键方法。本篇我们分析一下DefaultMessageStore提供的功能的具体实现。这里再把上篇的DefaultMessageStore功能清单贴出来:
我们本篇主要分析数据的写入和读取过程。
二、源码分析
1、数据写入
DefaultMessageStore数据写入的过程很简单,因为大部分逻辑都由CommitLog实现了。我们以public CompletableFuture asyncPutMessage(MessageExtBrokerInner msg) 方法为例,看一下数据写入的逻辑:
@Override
public CompletableFuture<PutMessageResult> asyncPutMessage(MessageExtBrokerInner msg) {
PutMessageStatus checkStoreStatus = this.checkStoreStatus();
if (checkStoreStatus != PutMessageStatus.PUT_OK) {
return CompletableFuture.completedFuture(new PutMessageResult(checkStoreStatus, null));
}
PutMessageStatus msgCheckStatus = this.checkMessage(msg);
if (msgCheckStatus == PutMessageStatus.MESSAGE_ILLEGAL) {
return CompletableFuture.completedFuture(new PutMessageResult(msgCheckStatus, null));
}
long beginTime = this.getSystemClock().now();
CompletableFuture<PutMessageResult> putResultFuture = this.commitLog.asyncPutMessage(msg);
putResultFuture.thenAccept((result) -> {
long elapsedTime = this.getSystemClock().now() - beginTime;
if (elapsedTime > 500) {
log.warn("putMessage not in lock elapsed time(ms)={}, bodyLength={}", elapsedTime, msg.getBody().length);
}
this.storeStatsService.setPutMessageEntireTimeMax(elapsedTime);
if (null == result || !result.isOk()) {
this.storeStatsService.getPutMessageFailedTimes().incrementAndGet();
}
});
return putResultFuture;
}
在消息写入之前,需要检查当前系统存储状态,主要检查一下内容:当前DefaultMessageStore是否已经被shutdown、当前节点是否是Slave、当前是否是可写状态(磁盘是否满)、当前写磁盘是否处于繁忙状态(正在进行的CommitLog写入操作耗时超过了pageCacheBusyTimeOutMills)。未通过上述检查则不能写入消息。
接着会检查消息是否合法,主要检查消息的大小。
最后会调用CommitLog的方法写入数据。不过我们不要忘记一件事。数据写入并不是终点,会有定时任务ReputMessageService不断检查CommitLog新写入的数据,对写入的消息建ConsumeQueue索引,并将消息响应消息客户端。
2、消息获取
消息获取接口分两类:1、根据精确的信息获取消息数据;2、根据时间搜索消息数据。
第一种获取消息是通过ConsumeQueue索引到CommitLog查询消息的。第二种是通过查询IndexFile查询消息的。
我们分别来看一下各自实现逻辑,以
GetMessageResult getMessage(final String group, final String topic, final int queueId, final long offset, final int maxMsgNums, final MessageFilter messageFilter)
为例,来看一下第一种情况:
public GetMessageResult getMessage(final String group, final String topic, final int queueId, final long offset,
final int maxMsgNums,
final MessageFilter messageFilter) {
// 省略部分代码
long beginTime = this.getSystemClock().now();
GetMessageStatus status = GetMessageStatus.NO_MESSAGE_IN_QUEUE;
long nextBeginOffset = offset;
long minOffset = 0;
long maxOffset = 0;
GetMessageResult getResult =