13.RocketMQ-MappedFile和MappedFileQueue

源文:https://blog.csdn.net/u014570939/article/details/123912678

MappedFile与MappedFileQueue

MappedFile内存映射类

commitLog,consumeQueue,indexFile文件都是基于mappedFile去管理本地磁盘文件;

mappedByteBuffer

mappedFile使用内存映射技术读写本地磁盘文件的,基于mmap/write系统调用;mmap提出来一个概念叫共享物理内存,用户空间中的一块数据缓冲区和内核空间中的一块内核缓冲区同时映射到了同一块物理内存,当用户读取数据时,调用mapp系统函数,若内核缓冲区无,则cpu委托DMA设备去磁盘中找,找到后,拷贝到内核缓冲区,由于有共享物理内存,所以用户空间直接可以读取共享物理内存,而不用再将数据从内核缓冲区拷贝到用户缓冲区;
可以通过File对象创建fileChannel,fileChannel是nio下访问文件的通道,通过fileChannel又可以创建出mappedByteBuffer,mappedByteBuffer会在当前进程的虚拟内存中开辟一块区间,区间大小和数据文件的大小是1比1的,虚拟内存与物理内存并没有提前映射好,当用户访问当前进程的虚拟内存中的某块时,会去进程中的页表中查询当前虚拟内存中的某块是否有对应的物理内存,若没有,则会产生缺页异常,接着会执行缺页的处理程序,该程序会去物理内存上找一空闲的页,将其地址存进页表中,此时即建立好了这块虚拟内存和物理内存之间的映射,但物理内存和内核空间之间还未形成映射,此时会执行mmap函数,执行系统调用,建立物理内存和内核空间的映射关系,并且将数据加载进物理内存中,此时用户就可以通过该块共享的物理内存访问到内核空间中的部分数据了;
当往磁盘文件中写数据时,数据会被写到进程虚拟内存对应的共享物理空间中,此时该页被称为脏页,操作系统会把该脏页刷进磁盘文件,此时调用mappedByteBuffer.force方法,会强制性地将该脏页数据刷进磁盘文件中;

wrotePosition,committedPosition,flushedPosition

wrotePosition和committedPosition是一个东西,只有当mappedFile不使用mappedByteBuffer时,才是用committedPosition,当mappedFile中的数据被写进自定义的byteBuffer时,再通过fileChannel的方式将数据写进文件时,才会使用committedPosition;mappedByteBuffer比自定义byteBuffer性能好;
wrotePosition和 flushedPosition均表示数据在mappedByteBuffer上的位点;
[0,flushedPosition]之间的数据表示已刷盘的数据,[flushedPosition,wrotePosition]之间的数据表示未刷盘的数据,即脏页数据,调用mappedByteBuffer.force方法会产生系统调用,让脏页数据落盘

与资源释放相关
  • refCount

MappedFile继承了ReferenceResource,当新建MappedFile实例时,AtomicInteger类型的refCount字段为1
当调用selectMappedBuffer(pos)查询数据时,会增加引用计数即refCount++,此时refCount为2,此时会创建mappedByteBuffer的切片副本,设置数据区间[pos,文件的截止位点]封装到SelectMappedBufferResult实例中,返回该副本给上层程序,切片buffer和mappedByteBuffer指向的是同一块虚拟内存中的同一块内存映射区间;当查询处理程序,处理完切片上的数据时,需要调用mappedFile.release方法,该方法会将refCount减1,此时refCount回到了为1,当refCount为0时,会调用cleanup方法;

  • 当mappedFile表示的文件不再使用时

会调用shutdown方法关闭资源,本质也是调用release方法,此时refCount会由1变为0,此时会调cleanup方法,会释放mappedByteBuffer,关闭fileChannel,更新静态变量,总映射虚拟内存的量,总映射内存文件数
cleanupover字段表示资源是否已经清理完毕,当调用cleanup方法后,该字段为true,表示当前的mappedFile对象已经废了,不能访问内存了;
MappedFile#destroy方法删除本地磁盘上的文件,并且把占用内存相关的资源全都释放掉,先会执行shutdown方法,随后会执行fileChannel.close方法和file.delete方法;

  • mappedFile的父类ReferenceResource

每次新建一个mappedFile,refCount就为1,若当前mappedFile中再次产生mappedByteBuffer的副本,则refCount会加1,变为2;
当调用ReferenceResource#hold方法时,会执行refCount++;
当调用ReferenceResource#release方法时,会执行refCount–,并且会判断若refCount不大于0,则会执行MappedFile#cleanup方法,清理资源;
当调用ReferenceResource#shutdown方法时,会先判断available是否为true,该值初始为true,只有在第一次执行shutdown方法时,才会被置为false,所以若为true,则记录当前时间到firstShutdownTimestamp中,接着执行release方法;若available为false,则判断refCount是否大于0,若大于0,则再判断当前时间减去firstShutdownTimestamp是否大于强制间隔时间,若大于,则将refCount置为负数,再执行release方法,此时由于refCount不大于0,所以会执行MappedFile#cleanup方法;

MappedFileQueue内存映射文件管理类

storePath表示管理的文件所在目录,如果是commitLog文件,则该值为…/store/commitlog,若是consumeQueue文件,则该值为…/store/consumequeue/xxx_topic/queueId表示某个topic下某个队列id中的文件;

顺序写

管理着…/store/commitlog文件夹下的所有mappedFile文件,每个mappedFile文件默认1g,不管来自broker的哪个topic哪个queueId的消息都会被顺序写入到mappedFile文件中;

commitLog中消息的存储格式
  • 文件尾标示

mappedFile文件中存储的每条消息大小不一,文件中最后一条消息后会紧跟8个特殊字节,前4个字节表示当前这个文件还剩多少空间,后4个字节是一个魔数表示当前文件已经到尾部了;

  • 具体有哪些字段

msgSize占4字节,代表当前消息的大小;
MAGICCODE占4字节,为daa320a7;
BODY CRC 占4字节,消息体BODY CRC,当broker重启时会校验;
queueId占4字节,消息队列id;
flag占4字节,供应用程序使用;
QUEUEOFFSET占8字节,队列逻辑偏移量,consumeQueue文件内真实的偏移量为QUEUEOFFSET*20,QUEUEOFFSET是topicQueueTable中的value,表示topic-queueId所对应的消息个数;
PHYSICALOFFSET 占8字节 代表消息在commitLog中的物理偏移量;
系统标示,消息生产端时间戳,生产端地址,在broker存储时间,存储在broker的地址,重复消费次数,事务消息物理偏移量;
消息体长度 占4字节
消息体内容
topic长度占1字节
topic内容
属性值长度占2字节
属性内容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值