源码分析RocketMQ之Broker-内存映射刷盘流程
内存映射:MappedFileQueue.getLastMappedFile
属性:
storePath:文件存储路径
mappedFileSize:单个MappedFile文件长度
CopyOnWriteArrayList<MappedFile> mappedFiles:mappedFile集合
allocateMappedFileService:创建 MappedFileService服务线程
flushedWhere:刷盘位置
committedWhere:commit(已提交)位置
storeTimestamp:存储时间
内存映射文件MappedFileQueue 组织一系列MappedFile,在MappedFileQueue 队尾的通常是刚写满的或者还有部分
空间或者是刚分配的MappedFile,每次写操作都通过getLastMappedFile拿到最后一个MappedFile进行写操作。
MappedFile 通过 AllocateMappedFileService 进行文件的创建操作。

MappedFile
属性变量:
TOTAL_MAPPED_VIRTUAL_MEMORY:当前jvm实例中MappedFile虚拟内存
TOTAL_MAPPED_FILES:当前jvm实例中MappedFile对象个数
wrotePosition:写入指针
committedPosition:提交指针
flushedPosition:刷写指针
fileSize:单个文件的大小
fileChannel:文件通道
writeBuffer:写入buffer,如果开启了 transientStorePoolEnable 时不为空,writeBuffer 使用堆外内存,消息先进入到堆外内存中
             然后通过Commit线程提交到内存映射buffer中,再通过Flush线程将数据持久化到磁盘中
transientStorePool:writeBuffer 池,只有在开启 transientStorePoolEnable 时生效,默认为5个
mappedByteBuffer:内存映射,操作系统的 PageCache
firstCreateInQueue:是否MappedFileQueue队列中第一个文件

Producer发送消息给broker的消息保存到MappedFile中,然后通过刷盘机制同步到磁盘中
刷盘分为同步刷盘和异步刷盘,刷盘操作通过MappedFile.commit和MappedFile.flush,MappedFile.flush 
通过fileChannel.force或者mappedByteBuffer.force()进行实际的刷盘动作
MappedFile.appendMessage 完成消息写入
1、获取写入位置
2、判断是否开启写入缓冲池,如果writeBuffer不为空,则优先写入writeBuffer,否则写入mappedByteBuffer
3、定位当前位置开始
4、对消息进行编码,然后将编码后的数据写入这里得到的buteBuffer等待刷盘
5、记录写入到的位置
6、更新存储时间
7、返回消息结果

MappedFile.commit 
1、如果 writeBuffer 等于null,则表示 IO 操作都是直接基于 FileChannel,所以此时返回当前可写的位置
2、判断是否可以执行提交操作
3、如果可以执行 commit0 
  1、这里使用 slice 方法,主要是用的同一片内存空间,但单独的指针
  2、将 bytebuf 当前 上一次 commitedPosition + 当前写位置这些数据全部写入到 FileChannel中
  3、fileChannel.write(byteBuffer) :commit 的作用原来是将writeBuffer 中的数据写入到 FileChannel 中
  4、更新committedPosition的位置
MappedFile.flush 调用 FileChannel 或 MappedByteBuffer 的 force 方法

单个commitlog文件,默认大小为1G,由多个commitlog文件来存储所有的消息,commitlog文件的命名以该文件在
整个commitlog中的偏移量来命名,如:
 第一个文件: 00000000000000000000
 第二个文件: 00000000000000001024
MappedFile 封装一个一个的commitlog文件,而MappedFileQueue 就是封装一个逻辑的commitlog文件,mappedFiled队列,从小到大排列
使用内存映射机制,MappedByteBuffer 具体封装类为MappedFile
同步刷盘,每次发送消息,都直接存储在MapFile 的 mappdByteBuffer,然后调用force()方法刷写到磁盘,等到 force 刷盘成功后,
再返回调用方GroupCommitRequest#waitForFlush,这就是同步调用实现
异步刷盘
分为两种情况是否开启堆外内存池
开启 消息追加时,放入writeBuffer 然后定时commit 到 FileChannel,然后定时flush。
不开启 消息追加时,直接存入 MappedByteBuffer(pageCache) 中,然后定时 flush