消息的物理文件布局与目录结构
了解了各个文件的作用现在我们来看看它们在实际磁盘上是如何组织在一起的。RocketMQ 在 Broker 的存储目录下默认是 ~/store有这样一个完整的文件布局~/store/ Broker 存储根目录TopicA 目录下consumequeue 目录每个 queue 目录下00000000000000000000约 5.72MBconsumequeue/消息的队列索引TopicATopicBTopicCcommitlog/所有消息的物理存储commitlog 目录000000000000000000001GB000000000010737418241GB000000000021474836481GBqueue0queue1queue2queue3index/Key 查询索引checkpoint刷盘检查点文件abort异常关闭标识各文件/目录的作用目录/文件 作用commitlog/ 存储所有消息的原始数据每个文件 1GB文件名起始偏移量consumequeue/{topic}/{queueId}/ 存储 ConsumeQueue 索引每个文件约 5.72MB300000 条索引index/ 存储基于 Key 的哈希索引文件用于消息查询checkpoint 记录最后一次刷盘的 CommitLog 和 ConsumeQueue 位置用于宕机恢复abort 文件存在表示 Broker 异常关闭启动时需要做恢复检查消息文件的滚动与清理策略RocketMQ 的文件不是无限增长的它有完善的滚动和清理机制。文件滚动策略CommitLog每个文件固定 1GB写满后自动创建新文件ConsumeQueue每个文件固定约 5.72MB包含 300000 条索引写满后自动创建新文件文件名的设计非常巧妙——用文件的起始偏移量作为文件名。这样通过任意一个偏移量你可以立刻算出它属于哪个文件偏移量 15,000,000,000 → 文件名取整 → 00000000001500000000文件清理策略RocketMQ 的文件清理由 CleanCommitLogService 和 CleanConsumeQueueService 两个后台服务负责清理的触发条件主要有三种是否是是否否是否文件清理检查磁盘空间是否超过阈值强制清理过期文件最先删除最老的文件当前文件是否已过期过期时间是否达到删除阈值删除过期文件删除周期是否到达跳过保留文件结束具体策略文件过期删除Broker 配置了 fileReservedTime默认 72 小时文件被创建后超过这个时间且文件不再被写入即不是当前活跃文件就会被删除磁盘空间强制删除当磁盘使用率超过 diskMaxUsedSpaceRatio默认 75%时会强制删除最老的文件即使文件还未达到过期时间手动触发通过管理控制台或 API 手动触发清理当前文件的保护正在写入的 CommitLog 文件当前活跃文件不会被删除即使它已经“过期”了。只有在文件滚动后旧文件才会进入待删除队列。消息的过期删除机制文件时间戳与删除策略RocketMQ 的消息过期删除本质上就是基于文件的删除而不是基于单条消息的删除。这和很多其他消息中间件不同。核心原理每个文件CommitLog 文件或 ConsumeQueue 文件都有一个最后修改时间戳当后台清理线程扫描时如果当前时间 - 文件最后修改时间 fileReservedTime默认 72 小时该文件就会被删除因为 CommitLog 中的消息是按时间顺序写入的所以删除文件 删除该时间点以前的所有消息为什么要这样设计基于文件的删除比基于消息的删除高效得多直接删除文件 vs. 遍历并标记删除RocketMQ 假设消息在保存一段时间后要么被消费了要么不再需要了这适用于大多数场景——消息是有“时效性”的过期了就应该被清理 小贴士如果你的业务有“长期保存消息”的需求比如审计场景可以设置更长的 fileReservedTime也可以将消息转存到其他存储系统如 OSS 或 HDFS进行长期归档。消息的零拷贝技术原理MMAP FileChannel接下来我们聊聊 RocketMQ 的性能黑科技——零拷贝。什么是零拷贝传统的文件读取 → 网络发送数据要经历多次拷贝从磁盘读到内核空间DMA 拷贝从内核空间读到用户空间CPU 拷贝从用户空间写到 Socket 缓冲区CPU 拷贝从 Socket 缓冲区写到网卡DMA 拷贝—— 4 次拷贝2 次 CPU 参与CPU 被占用做数据搬运效率低。零拷贝技术是指通过操作系统的 sendfile 或 mmap 系统调用减少数据在内核空间和用户空间之间的拷贝次数。RocketMQ 在写入和读取两个场景分别使用了不同的零拷贝技术写入场景MMAP内存映射文件RocketMQ 使用 FileChannel 的 map() 方法将 CommitLog 文件映射到操作系统的虚拟内存中PageCache 的映射。