rocketMQ消息存储源码

本文深入探讨RocketMQ的消息存储结构,包括DefaultMessageStore、CommitLog、MappedFileQueue和MappedFile等组件。讲解了消息从写入到刷盘的过程,以及consumeQueue、索引文件的构造和刷盘策略。此外,还涵盖了文件过期清理机制和不同刷盘模式的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要存储文件包括

  • 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

  1. transientStorePoolEnable不为true时,通过radomFileAccess创建文件通道
this.fileChannel = new RandomAccessFile(this.file, “rw”).getChannel();
this.mappedByteBuffer = this.fileChannel.map(MapMode./READ_WRITE/, 0, fileSize);
  1. transientStorePoolEnable=true时先初始化writeBuffer
this.writeBuffer = transientStorePool.borrowBuffer();
this.transientStorePool = transientStorePool;

提交(从write buffer->FileChannel)

commit方法

ByteBuffer byteBuffer = writeBuffer.slice();
byteBuffer.position(lastCommittedPosition);
byteBuffer.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值