CommitLog 是 RocketMQ 所有消息的唯一顺序写入文件,按 1GB 分片、全局物理偏移命名;ConsumeQueue 是其异步构建的消费索引,按 Topic/Queue 分离存储;刷盘分同步与异步,影响可靠性与吞吐;消息按 Broker 粒度统一按时间(默认 72 小时)清理,与消费状态无关。

CommitLog 是所有消息的“唯一落盘入口”
RocketMQ 不像 Kafka 那样按 Topic-Queue 分文件存储,而是把所有 Topic 的所有消息,不分彼此,**顺序追加写入同一个 CommitLog 文件**。这是它高性能写入的核心——磁盘顺序写远快于随机写。
每个 CommitLog 文件默认 1GB,文件名是 20 位数字,代表该文件第一条消息在全局日志中的物理偏移量(offset),比如 00000000000000000000、00000000001073741824(即 1GB 后)。
消息体写入时带 CRC 校验、长度、时间戳等字段,格式固定,便于后续解析。
- 别指望靠文件系统直接“看懂”消息内容——
CommitLog是二进制流,必须通过 RocketMQ 客户端或mqadmin工具解析 - Broker 异常宕机后未刷盘的消息会丢失,是否丢取决于刷盘策略(见下一条),跟 CommitLog 文件本身无关
- 单个 Broker 实例下所有 Queue 共享同一套 CommitLog,所以不能通过删某个 Topic 的文件来“清理数据”——那是破坏性操作
ConsumeQueue 是消费端的“高效索引表”
ConsumeQueue 不存消息体,只存三条关键元数据:commitLogOffset(在 CommitLog 中的位置)、msgSize(大小)、tagHash(Tag 的哈希值)。它按 Topic/QueueId 组织,每个队列一个独立文件,每条记录固定 20 字节。
- 消费者拉取消息时,先顺序读
ConsumeQueue,拿到 offset 后再去CommitLog随机读取真实消息——这叫“逻辑顺序、物理随机”,但因批量预读 + page cache,实际性能很好 -
ConsumeQueue是异步构建的:消息写入 CommitLog 成功后,后台线程才更新对应 ConsumeQueue。极端情况下(如 Broker 崩溃),ConsumeQueue 可能滞后几条,但不会错位 - 它的文件大小不固定,但单个文件默认最多存约 600 万条索引项;达到上限后滚动新建,文件名也是以起始 offset 命名
刷盘策略决定“消息到底算不算落库”
消息写入 MappedFile(内存映射区)只是第一步,真正持久化到磁盘靠的是刷盘。RocketMQ 提供两种模式:SYNC_FLUSH 和 ASYNC_FLUSH,由 flushDiskType 配置项控制。
-
SYNC_FLUSH:生产者发完消息后,必须等force()调用完成、数据真正落盘,才返回成功。可靠性最高,但吞吐低、延迟高,适合金融类强一致场景 -
ASYNC_FLUSH:消息写进内存就返回成功,后台线程按 16KB 数据量或 500ms 时间间隔触发刷盘。吞吐高,但 Broker 突然断电可能丢失最后一批未刷盘消息 - 注意:
TransientStorePoolEnable=true时,消息先写堆外内存池再进 MappedFile,可缓解 GC 压力,但和刷盘策略正交,不是替代关系
消息过期清理只看时间,不管有没有被消费
RocketMQ 的消息保留机制非常简单粗暴:**按 Broker 节点粒度,统一设置 fileReservedTime(默认 72 小时)**。只要消息的 storeTimestamp 超过这个时间,无论是否被消费、是否堆积、是否重试过,都会被定时任务扫描并物理删除。
立即学习“Java免费学习笔记(深入)”;
- 不会因为某条消息没被消费就延长保留——它和消费状态完全解耦,这是设计使然,不是 bug
- 想延长保留?只能改配置重启 Broker,且整个节点所有消息一起延,无法按 Topic 或 Group 单独设置
- 如果业务需要超长留存(比如 30 天),建议另建专用集群,避免影响主链路 SLA 和磁盘容量水位

















