都存什么
- commitLog文件
- consumeQueue文件
- indexFile文件
- 报错文件等等
存在哪
存在每个broker的磁盘中
commitLog文件
是什么?
消息真正存储的地方。消息发送到broker的时候。先存储到commitLog,broker存储到commitLog后就通知producer消息发送成功了。commitLog到consmeQueue是broker的分发策略去做的。
存储结构
存在 rocketmq/store/commitlog文件夹中。
以offset为文件名,存储message。
每个文件默认都是1G。一个文件写满后,创建另外一个文件,以该文件的第一个message的偏移量命名。文件名20位,不够补0。
因为。message的大小(长度)是固定的,所以可以通过offset快速找到文件,再通过长度快速找到这条消息。这里和数组很像,存数组头的地址信息,后面寻址,直接用数组头+偏移量直接就能找到。
commitLog不是永久落盘的。默认存活时间是72小时,超过72小时,就标记为失效文件,默认每天凌晨4点清除失效文件。
是直接落盘么
肯定不是啊。中间有一层buffer(NIO内存映射问文件)
MapperFileQueue相当于commitlog这个文件夹
MapperFile相当于commitlog文件夹下的每个文件
消息发送到后,先存在这个内存变量中,根据刷磁盘策略,往磁盘中刷数据。也就是刷脏页。
刷脏页策略:
- 同步:写入buffer,马上刷脏页,然后再返回producer消息发送成功。这样,能防止发送阶段消息不丢失。
- 异步:写入buffer,就返回producer消息发送成功。然后根据broker的刷脏页策略来刷脏页。
异步刷脏页策略
rocketMq有两个参数去控制
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0
vm.dirty_expire_centisecs = 3000
vm.dirty_ratio = 30
vm.dirty_writeback_centisecs = 500
vm.dirty_background_ratio = 10
当脏页数量达到系统内存10%时就会触发pdflush/flush/kdmflush等后台进程,将一部分缓存的脏页异步的刷进磁盘。
vm.dirty_ratio = 30
当脏页数量达到系统内存30%时,系统开始同步的将脏页刷入磁盘,同时会阻塞其他进程的写操作。
10/30是系统默认值,可以自己根据业务情况设置。
写的过程是什么
因为存在一个地方(commitLog),所以消息必须要顺序写。每次写请求进入后,先拿写锁,阻塞顺序写。
consumeQueue文件
是什么
这个是真正的mq的队列。里面不存具体的消息,而是存消息的指针。这个指针指向commitlog中该消息的位置。
这样做的好处是:
1、扩展性好。消息的真是数据存在一个地方,不会根据queue的变动而变动。
2、查询速度快。
存储结构
第一层是topic。
第二层是topic下queue队列id。
第三层是队列下的消息文件。
单个ConsumerQueue文件中默认包含30万个条目,单个文件的长度为30W * 20字节。
commitlog在向consumerQueue转发的时候,会根据producer中的send策略,判断转发到哪个队列中。
策略包括:轮训、随机、key hash。
怎么查找
consumeQueue可以理解为写队列。
针对于查找还会有一个读队列processQueue。
每个消费者group,都会有隔离的一组队列,通过processQueue做到的每个group的隔离。
消费者根据 offset和tag拉consumerQueue的数据 到 processQueue,最终消费的是processQueue。processQueue是每个组隔离的。
indexFile索引文件
是什么
是commitLog的索引文件。与queue队列无关。单纯的commitLog以key为索引的索引文件。
slot table存的是key的hash值。也就是后面index的索引。有hash冲突怎么办,这里就不是链表法了,用的是二次hash来解决hash冲突。
index linked list: 存的是具体的索引。
index linked list: 存的是具体的索引。
key hash: message key的hash值
phyOffset: message在commitlog的物理文件地址,可以直接查询到该消息(存储的核心机制)
timeDiff:message的落盘时间与header里的beginTimestamp的差值(为了节省存储空间,如果直接存message的落盘时间就得8bytes)
prevIndex: hash冲突处理的关键之处,相同hash值上一个消息索引的index(如果当前消息索引是该hash值的第一个索引,则prevIndex=0, 也是消息索引查找时的停止条件。)