主要存储文件包括
- commitLog存储所有topic的所有消息,确保消息顺序
- consumeQueue文件,每个topic包括多个consumeQueue,每个consumeQueue有一个消息文件。供消费者消费
- indexFile,根据消息属性快速从commitLog中索引消息,存储消息key和commitLog中offset的对应关系
DefaultMessageStore
-
private final MessageStoreConfig messageStoreConfig;
- 消息存储配置属性
-
private final CommitLog commitLog;
- commitLog文件实现类
-
private final ConcurrentMap<String/* topic /, ConcurrentMap<Integer/ queueId */, ConsumeQueue>> consumeQueueTable;
- 消息消费队列缓存,按照topic分组
-
private final FlushConsumeQueueService flushConsumeQueueService;
- 消息队列文件consumeQueue刷盘服务
-
private final CleanCommitLogService cleanCommitLogService;
- 清除commitLog服务
-
private final CleanConsumeQueueService cleanConsumeQueueService;
- 清除comsumeQueue服务
-
private final IndexService indexService;
- 索引文件实现类
-
private final AllocateMappedFileService allocateMappedFileService;
- 分配服务
-
private final ReputMessageService reputMessageService;
- 根据commitLog文件构建consumeQueue和indexFile文件
-
private final HAServicehaService;
- 存储HA机制
-
private final ScheduleMessageService scheduleMessageService;
-
private final StoreStatsService storeStatsService;
-
private final TransientStorePool transientStorePool;
- 消息堆内缓存
CommitLog
文件形式为1G一个的文件,每个文件以第一个消息偏移量命名,所有文件对应mappedFileQueue对象,相当于存储目录,每个文件对应MappedFile对象
putMessage方法
doAppend方法只是将消息追加在内存中,要根据异步刷盘还是同步刷盘来将内存中的数据同步到磁盘中。
MappedFileQueue
- storePath; —存储目录
- mappedFileSize; —单个文件大小
- CopyOnWriteArrayList mappedFiles = new CopyOnWriteArrayList(); —文件集合
- AllocateMappedFileService allocateMappedFileService;—创建MapedFile服务类
- private long flushedWhere = 0;—当前刷盘指针,在这之前的数据都已经刷盘
- private long committedWhere = 0; —当前提交的指针,内存ByteBuffer当前的写指针,>= flushedWhere
获取MappedFile方式
- getMappedFileByTime根据时间
- findMappedFileByOffset
根据偏移量,由于使用了内存映射,所有存储在目录下的文件都需要创建对应的内存映射文件,如果不定时把已经消费的文件删除会造成大量的内存压力的资源浪费,因此文件初始偏移量不是总从0开始
MapedFile
- public static final int OS_PAGE_SIZE= 1024 * 4; —操作系统每页大小,默认4K
- private static final AtomicLong TOTAL_MAPPED_VIRTUAL_MEMORY= new AtomicLong(0); —当前JVM中已经map的虚拟内存
- private static final AtomicInteger TOTAL_MAPPED_FILES= new AtomicInteger(0);--当前JVM中已经map的MappedFIle对象个数
- protected final AtomicInteger wrotePosition= new AtomicInteger(0);
//ADD BY ChenYang --当前文件的写指针(writeBuffer) - protected final AtomicInteger committedPosition = new AtomicInteger(0);--当前文件的提交指针
- private final AtomicInteger flushedPosition = new AtomicInteger(0); -刷写道磁盘的指针
- protected int fileSize;--文件大小
- protected FileChannel fileChannel; --文件通道
//**/
/ * Message will put to here first, and then rebut to FileChannel if writeBuffer is not null./
/ *// - protected ByteBuffer writeBuffer = null; --堆内存byte buffer,如果不为空(transientStorePoolEnable=true),则提交的数据先缓存在这里,再提交到mappedFIle对应的内存映射文件buffer
- protected TransientStorePool transientStorePool= null; --堆内存池,ransientStorePoolEnable=true时启用
- private String fileName;--文件名
- private long fileFromOffset;--文件初始偏移量,也就是文件名
- private File file;--物理文件
- private MappedByteBuffer mappedByteBuffer; --物理文件对应的内存映射buffer
- private volatile long storeTimestamp = 0; --文件最后一次写入时间
- private boolean firstCreateInQueue = false; --是否时mappedFileQUe队列中第一个
transientStorePoolEnable默认为false,表示采用mmap+write的零拷贝技术,为true时,表示使用sendfile零拷贝技术,多了一个commit流程
- transientStorePoolEnable=true
数据流向:数据——》writeBuffer——》fileChannel——》force到磁盘 - transientStorePoolEnable=false
数据流向:数据-》mappedFileBuffer-》force到磁盘
init
- transientStorePoolEnable不为true时,通过radomFileAccess创建文件通道
this.fileChannel = new RandomAccessFile(this.file, “rw”).getChannel();
this.mappedByteBuffer = this.fileChannel.map(MapMode./READ_WRITE/, 0, fileSize);
- transientStorePoolEnable=true时先初始化writeBuffer
this.writeBuffer = transientStorePool.borrowBuffer();
this.transientStorePool = transientStorePool;
提交(从write buffer->FileChannel)
commit方法
ByteBuffer byteBuffer = writeBuffer.slice();
byteBuffer.position(lastCommittedPosition);
byteBuffer.