RocketMQ源码分析(十三)之ConsumeQueue

本文深入分析RocketMQ的ConsumeQueue,包括其作为索引文件的角色、消息加载与恢复过程、消息追加以及ReputMessageService和CommitLogDispatcher的工作原理。ConsumeQueue的每个实例对应一个queueId,存储格式为20B,包含消息的offset等信息,用于消费者定位CommitLog中的原始消息。
摘要由CSDN通过智能技术生成

版本

  1. 基于rocketmq-all-4.3.1版本

ConsumeQueue

  1. 每个ConsumeQueue都有一个queueId,queueId 的值为0到TopicConfig配置的队列数量。比如某个Topic的消费队列数量为4,那么四个ConsumeQueue的queueId就分别为0、1、2、3。

  2. ConsumerQueue相当于CommitLog的索引文件,消费者消费时会先从ConsumerQueue中查找消息在CommitLog中的offset,再去CommitLog中找原始消息数据。如果某个消息只在CommitLog中有数据,没在ConsumerQueue中, 则消费者无法消费

  3. Consumequeue类对应的是每个topic和queuId下面的所有文件.默认存储路径是**$HOME/store/consumequeue/{topic}/{queueId}/{fileName},每个文件由30w条数据组成,单个文件的大小是30w x 20Byte**

  4. 每一个ConsumeQueue存储的格式为commitLogOffset(8B)+size(4B)+tagHashCode(8B),总共20B。存tag是为了在Consumer取到消息offset后先根据tag做一次过滤,剩下的才需要到CommitLog中取消息详情

  5. ConsumeQueue核心属性

    public class ConsumeQueue {
         
       private final DefaultMessageStore defaultMessageStore;
       //映射文件队列,管理ConsumeQueue
       private final MappedFileQueue mappedFileQueue;
       // 消息topic
       private final String topic;
       // 消息队列Id
       private final int queueId;
       //指定大小的缓冲,记录的大小是20byte的固定大小
       private final ByteBuffer byteBufferIndex;
       //保存的路径
       private final String storePath;
       //映射文件的大小
       private final int mappedFileSize;
       //最后一个消息对应的物理偏移量  也就是在CommitLog中的偏移量
       private long maxPhysicOffset = -1;
       //最小的逻辑偏移量 在ConsumeQueue中的最小偏移量
       private volatile long minLogicOffset = 0;
       //ConsumeQueue的扩展文件
       private ConsumeQueueExt consumeQueueExt = null;
    }   
    
  6. 构造方法

    public ConsumeQueue(
        final String topic,
        final int queueId,
        final String storePath,
        final int mappedFileSize,
        final DefaultMessageStore defaultMessageStore) {
         
        this.storePath = storePath;
        this.mappedFileSize = mappedFileSize;
        this.defaultMessageStore = defaultMessageStore;
    
        this.topic = topic;
        this.queueId = queueId;
        //存储路径${this.storePath}/{topic}/{queueId}/{fileName}
        String queueDir = this.storePath
            + File.separator + topic
            + File.separator + queueId;
    
        this.mappedFileQueue = new MappedFileQueue(queueDir, mappedFileSize, null);
        //分配一个存储单元大小(20B)的缓冲区
        this.byteBufferIndex = ByteBuffer.allocate(CQ_STORE_UNIT_SIZE);
        //是否启用消息队列的扩展存储
        if (defaultMessageStore.getMessageStoreConfig().isEnableConsumeQueueExt()) {
         
            this.consumeQueueExt = new ConsumeQueueExt(
                topic,
                queueId,
                StorePathConfigHelper.getStorePathConsumeQueueExt(defaultMessageStore.getMessageStoreConfig().getStorePathRootDir()),
                defaultMessageStore.getMessageStoreConfig().getMappedFileSizeConsumeQueueExt(),
                defaultMessageStore.getMessageStoreConfig().getBitMapLengthConsumeQueueExt()
            );
        }
    }
    

加载(load)

  1. Broker启动时,调用load加载ConsumeQueue。加载直接委托mappedFileQueue进行加载

    public boolean load() {
         
        boolean result = this.mappedFileQueue.load();
        log.info("load consume queue " + this.topic + "-" + this.queueId + " " + (result ? "OK" : "Failed"));
        //扩展存储存在则加载
        if (isExtReadEnable()) {
         
            result &= this.consumeQueueExt.load();
        }
        return result;
    }
    

恢复(recover)

  1. Broker启动时会尝试恢复ConsumeQueue文件。

    • 如果文件个数大于3个就从倒数第三个文件开始恢复,否则从第一个开始
    • 循环遍历文件中的的所有数据,按照20个字节读取。知道全部读取完成
    • 删除有效offset之后的文件
  2. 源码

    public void 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值