这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 ConsumeQueue 把 CommitLog 中的物理消息组织成 Topic 和 Queue 的逻辑视图,IndexFile 提供按 Key 和时间查询的索引。两者都是派生数据,但它们直接决定消费效率和问题排查效率。
15.1 ConsumeQueue 结构
每个 Topic 的每个队列对应一个 ConsumeQueue 目录:
store/consumequeue/OrderTopic/
0/
1/
2/
3/
每个条目通常包含:
CommitLog offset
message size
tag hashcode
消费者流程:
read ConsumeQueue entry
-> get CommitLog offset and size
-> read message from CommitLog
15.2 逻辑位点
消费者位点指的是队列中的逻辑偏移:
Queue offset: 0, 1, 2, 3 ...
Broker 最大位点来自 ConsumeQueue 条目数:
Broker Offset = ConsumeQueue entries
Delayed = Broker Offset - Consumer Offset
同一个逻辑位点在不同 Broker 或重建后的集群中不一定指向相同物理消息,因此迁移和重放要格外谨慎。
15.3 Tag 过滤
ConsumeQueue 条目中保存 Tag hashcode,Broker 可以先做粗过滤:
consumer subscribes TagA
-> compare entry tag hashcode
-> candidate message sent to consumer
-> client validates real tag
特点:
- 减少不必要消息传输;
- hash 冲突由客户端最终校验;
- 订阅关系必须一致;
- Tag 修改会影响过滤效果;
- 复杂表达式会消耗 Broker CPU。
15.4 IndexFile
IndexFile 支持按消息 Key 和时间范围查询:
query key = O202608250001
-> hash to slot
-> scan index entry list
-> filter by key and time
-> read CommitLog
常见字段:
- key hash;
- CommitLog offset;
- message size;
- timestamp;
- index chain。
IndexFile 便于排查,不是业务数据库查询引擎。高频业务查询应使用数据库或搜索引擎,而不是依赖消息索引。
15.5 索引构建
Broker 在消息写入 CommitLog 后异步分发:
CommitLog append
-> ReputMessageService
-> build ConsumeQueue
-> build IndexFile
如果分发落后,可能出现:
- 消息已写入但消费者暂时看不到;
- 按消息 ID 查询和按 Key 查询结果不一致;
- Broker 流量高时索引构建延迟。
监控 dispatch lag 和队列最大位点,避免误判消息丢失。
15.6 重建与恢复
ConsumeQueue 和 IndexFile 理论上可以从 CommitLog 重建:
scan CommitLog
-> parse message
-> rebuild queue index
-> rebuild key index
注意:
- 重建需要磁盘、CPU 和时间;
- 必须先备份原始 CommitLog;
- 重建期间影响服务;
- 需要验证队列位点;
- 严格按当前版本运维手册操作;
- 有副本时优先从副本恢复。
15.7 容量规划
估算:
ConsumeQueue size ≈ queue message count × entry size
Index size ≈ key count × index entry size × expansion factor
CommitLog size ≈ message body + overhead
规划时还要考虑:
- Topic 数量;
- 队列数量;
- 消息大小;
- Key 数量;
- 保留时间;
- 重试和死信;
- 轨迹 Topic;
- 运维余量。
15.8 常见问题
| 问题 | 排查 |
|---|---|
| 消费者看不到新消息 | ConsumeQueue 构建延迟、位点、权限 |
| 按 Key 查不到 | 未设置 Key、索引延迟、索引过期 |
| 延迟突然增大 | 消费慢、Index 冷读、磁盘瓶颈 |
| 磁盘被索引占满 | Topic、队列或 Key 过多 |
| 队列位点不一致 | 异常关机、手工重置、迁移 |
| 重建后查询异常 | 索引不完整或时间范围错误 |
本章小结
ConsumeQueue 是 Topic 队列的逻辑索引,Index 是面向排查的 Key 和时间索引。它们让 RocketMQ 兼顾顺序写吞吐和多维度读取,但也带来构建延迟、容量和恢复复杂度。生产治理要同时关注 CommitLog、ConsumeQueue、Index 和消费位点的一致性。
思考题
- 消费位点为什么是队列逻辑位点而不是 CommitLog 偏移量?
- Tag 粗过滤为什么仍需要客户端校验?
- Index 为什么不适合作为业务查询引擎?
- dispatch lag 会造成什么误判?
- 重建索引前为什么必须备份 CommitLog?