西数云存储 重置 使用手册_rocketmq存储篇

7df18de050963c2196aa9381f71d968e.png

前言

消息存储是消息队列中最基础也是最重要的一部分服务,将会对rocketmq存储的整体架构剖析,分析存储、索引服务如何协同工作的?

存储整体架构

dd70c2d719d368954556fc5f0b6ecc1b.png

消息存储架构图中主要有下面三个跟消息存储相关的文件构成。

92f5627b447aabad97aaf525fe1fc956.png

(1) CommitLog:消息主体以及元数据的存储主体,存储Producer端写入的消息主体内容,消息内容不是定长的。单个文件大小默认1G ,文件名长度为20位,左边补零,剩余为起始偏移量,比如00000000000000000000代表了第一个文件,起始偏移量为0,文件大小为1G=1073741824;当第一个文件写满了,第二个文件为00000000001073741824,起始偏移量为1073741824,以此类推。消息主要是顺序写入日志文件,当文件满了,写入下一个文件;

(2) ConsumeQueue:消息消费队列,引入的目的主要是提高消息消费的性能,由于RocketMQ是基于主题topic的订阅模式,消息消费是针对主题进行的,如果要遍历commitlog文件中根据topic检索消息是非常低效的。Consumer即可根据ConsumeQueue来查找待消费的消息。其中,ConsumeQueue(逻辑消费队列)作为消费消息的索引,保存了指定Topic下的队列消息在CommitLog中的起始物理偏移量offset,消息大小size和消息Tag的HashCode值。consumequeue文件可以看成是基于topic的commitlog索引文件,故consumequeue文件夹的组织方式如下:topic/queue/file三层组织结构,具体存储路径为:$HOME/store/consumequeue/{topic}/{queueId}/{fileName}。同样consumequeue文件采取定长设计,每一个条目共20个字节,分别为8字节的commitlog物理偏移量、4字节的消息长度、8字节tag hashcode,单个文件由30W个条目组成,可以像数组一样随机访问每一个条目,每个ConsumeQueue文件大小约5.72M;

(3) IndexFile:IndexFile(索引文件)提供了一种可以通过key或时间区间来查询消息的方法。Index文件的存储位置是:$HOME \store\index\${fileName},文件名fileName是以创建时的时间戳命名的,固定的单个IndexFile文件大小约为400M,一个IndexFile可以保存 2000W个索引,IndexFile的底层存储设计为在文件系统中实现HashMap结构,故rocketmq的索引文件其底层实现为hash索引。

Commitlog存储格式

d77a22566d483ba93dedc5864c120381.png

Commitlog存储消息元数据,消息长度取决于消息内容body长度、Topic长度、拓展字段长度。Commitlog建立在MappedFile抽象了FileChannel以及MappedByteBuffer持久化能力的基础上,支持消息查询、根据offset查询等能力,并且利用AbstactMessageCallback拓展消息元数据持久化方式,使得持久化方式与MappedFile解耦。

// org.apache.rocketmq.store.CommitLog#calMsgLengthprotected static int calMsgLength(int bodyLength, int topicLength, int propertiesLength) {        final int msgLen = 4 //TOTALSIZE            + 4 //MAGICCODE            + 4 //BODYCRC            + 4 //QUEUEID            + 4 //FLAG            + 8 //QUEUEOFFSET            + 8 //PHYSICALOFFSET            + 4 //SYSFLAG            + 8 //BORNTIMESTAMP            + 8 //BORNHOST            + 8 //STORETIMESTAMP            + 8 //STOREHOSTADDRESS            + 4 //RECONSUMETIMES            + 8 //Prepared Transaction Offset            + 4 + (bodyLength > 0 ? bodyLength : 0) //BODY            + 1 + topicLength //TOPIC            + 2 + (propertiesLength > 0 ? propertiesLength : 0) //propertiesLength            + 0;        return msgLen;    }

在commitlog中,{ msg * * * }形式存储,如果新增msg消息导致文件不足以存放,那么设置BLANK_MAGIC_CODE说明是blank片段,并且记录下当前的时间戳;反之,如果足够存放,那么就会设置MESSAGE_MAGIC_CODE说明是msg片段。

289ee97d7666a248e6620bdcfa6952e5.png

如何更新消费队列或者索引文件?

消息存储服务启动时会加载消费队列目录,根据consumqueue最大的物理偏移计算reputOffset,如果迁移broker数据时未迁移consumqueue或者consumqueue目录磁盘损坏等情况,会重置 reputOffset ,也即会重建消费队列以及索引文件indexfile。reputMessageService 根据 reputOffset位置开始 对 消息元数据 解析生成 dispatchRequest已注册的CommitLogDispatcherBuildConsumeQueue以及 CommitLogDispatcherBuildIndex 建立consumqueue、index。

// org.apache.rocketmq.store.DefaultMessageStore// 注册解析器this.dispatcherList.addLast(new CommitLogDispatcherBuildConsumeQueue());this.dispatcherList.addLast(new CommitLogDispatcherBuildIndex());// 调度解析public void doDispatch(DispatchRequest req) {        for (CommitLogDispatcher dispatcher : this.dispatcherList) {            dispatcher.dispatch(req);        }    }

IndexFile存储格式

55b582774a09330aa4a6894647a1fd00.png

IndexFile索引文件为用户提供通过“按照Message Key查询消息”的消息索引查询服务,IndexFile文件的存储位置是:$HOME\store\index\${fileName},文件名fileName是以创建时的时间戳命名的,文件大小是固定的,等于40+500W\*4+2000W\*20= 420000040个字节大小。如果消息的properties中设置了UNIQ_KEY这个属性,就用 topic + “#” + UNIQ_KEY的value作为 key 来做写入操作。如果消息设置了KEYS属性(多个KEY以空格分隔),也会用 topic + “#” + KEY 来做索引。

索引数据包含了Key Hash/CommitLog Offset/Timestamp/NextIndex offset 这四个字段,一共20 Byte。NextIndex offset 即前面读出来的 slotValue,如果有 hash冲突,就可以用这个字段将所有冲突的索引用链表的方式串起来了。Timestamp记录的是消息storeTimestamp之间的差,并不是一个绝对的时间。整个Index File的结构如图,40 Byte 的Header用于保存一些总的统计信息,4\*500W的 Slot Table并不保存真正的索引数据,而是保存每个槽位对应的单向链表的头。20\*2000W 是真正的索引数据,即一个 Index File 可以保存 2000W个索引。

ConsumeQueue存储格式

984ee06b9c44150c6fecbabb20024e95.png

consumequeue 组织方式采用topic/queue/file,可以在consumer针对主题消费时提高消费速度,而消费的进度会持久化在/store/config/consumerOffset.json 。

6220f1b1e15565072b71a735b9d89114.png

文件存储格式定长设计,8字节的commitlog物理偏移量、4字节的消息长度、8字节tag hashcode,可以快速读取topic下所有的offset,无须遍历commitlog再去筛选数据,提高消费的能力。

后续

本文分析了rocketmq 元数据文件、索引文件的存储格式以及这种混合存储的优势可以提高消费能力、按主题消费等,而这些都建立在通用的存储能力MappedFile 之上,后续会针对pagecache的原理进行剖析,可以持续关注一波!

你的关注和转发就是对我最大的支持!

近期热文:

异地多活场景下的数据同步之道

Linux 技巧:让进程在后台运行更可靠的几种方法

聊聊代码规范

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值