RocketMQ存储之DefaultMessageStore(二)

一、概述

上篇分析了DefaultMessageStore的大体功能和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 =
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值