RocketMQNotes

第 30 章:面试题精讲

zjc 于 2026-01-30 发布

这是《RocketMQ 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 本章按“基础、存储、消息类型、高可用、性能、项目治理”整理高频问题。回答面试题时,最好先给结论,再讲机制,最后补生产实践和边界条件。

30.1 NameServer 和 Broker 的关系是什么?

NameServer 维护路由信息,Broker 定期注册并上报 Topic 队列数据,客户端从 NameServer 获取路由后直连或通过 Proxy 访问 Broker。

回答要点:

  1. NameServer 是轻量路由中心;
  2. Broker 承担消息存储和请求处理;
  3. NameServer 节点之间通常不强同步,客户端会综合路由视图;
  4. NameServer 宕机不立即影响已有连接;
  5. 新路由发现和拓扑更新会受影响。

加分项:说明 5.x Controller 与高可用架构演进。

30.2 RocketMQ 如何保证消息不丢?

分层回答:

producer send + retry + local compensation
broker flush + replication
consumer consume success + idempotent
platform monitoring + reconciliation

关键点:

  1. 生产端确认 SendStatus;
  2. 重要消息配合 Outbox 或事务消息;
  3. Broker 使用满足 SLA 的刷盘和副本策略;
  4. 消费成功后再确认;
  5. 所有链路有对账;
  6. 断电、磁盘损坏、机房故障需要不同方案。

不存在的万能开关,可靠性和成本必须一起讨论。

30.3 RocketMQ 为什么会重复消费?

典型场景:

  1. 发送超时后内部重试;
  2. 消费成功但位点提交失败;
  3. 消费超时触发重试;
  4. 死信重放;
  5. 补偿任务和消息并发。

处理方式:使用 eventId 或业务唯一键幂等,业务表用唯一约束或状态机条件更新。Redis 可作为优化,不能作为唯一保障。

30.4 顺序消息如何保证顺序?

三个条件:

same key -> same queue
same queue -> orderly consume
failure -> bounded retry

回答时说明局部顺序和全局顺序,队列选择器、MessageListenerOrderly、重试挂起和扩缩容影响。大多数业务只需要订单号、账号或 SKU 级局部顺序。

30.5 事务消息的流程是什么?

流程:

send half message
  -> execute local transaction
  -> commit or rollback
  -> unknown then checkback

关键点:

  1. 半消息对消费者不可见;
  2. 本地事务必须可回查;
  3. 回查不能依赖内存状态;
  4. 消费失败不会回滚生产端本地事务;
  5. 通常与本地事件表配合;
  6. 它是最终一致,不是分布式强事务。

30.6 延迟消息的原理和限制是什么?

4.x 以固定延迟级别为主,Broker 按级别调度后投递到真实 Topic。5.x 增强定时消息能力,可按时间触发。

限制:

  1. 到期精度受调度和消费能力影响;
  2. 版本能力差异大;
  3. 最大延迟时间可能有限制;
  4. 相同到期时间会造成洪峰;
  5. 业务仍需状态机幂等。

30.7 CommitLog、ConsumeQueue、IndexFile 的关系是什么?

CommitLog: physical message body
ConsumeQueue: topic queue logical index
IndexFile: key/time query index

回答要点:

  1. 所有 Topic 消息顺序追加 CommitLog;
  2. ConsumeQueue 保存 CommitLog offset、size 和 tag hash;
  3. IndexFile 支持按 Key 和时间查询;
  4. 索引由 ReputMessageService 异步构建;
  5. dispatch lag 可能造成短暂不可见。

30.8 刷盘和复制策略如何选择?

策略 目的
同步刷盘 降低宿主机断电丢失风险
异步刷盘 提升吞吐
同步复制 降低节点故障丢失风险
异步复制 降低延迟和带宽成本

核心是业务 RPO 与延迟预算。交易类偏可靠,日志类可偏成本。必须结合磁盘、网络和故障演练验证。

30.9 Broker 主从切换为什么可能丢消息?

异步复制下,主节点返回成功但部分尾部消息尚未复制到从节点。主节点磁盘损坏并切换到落后副本时,这部分消息可能不可恢复。

防范:

  1. 核心链路使用同步复制;
  2. 监控副本差距;
  3. 自动切换选择位点最新副本;
  4. 使用 Controller 或共识模式;
  5. epoch fencing 防脑裂;
  6. 保留业务级对账。

30.10 消费者数量和队列数量的关系是什么?

集群消费下,队列是最小分配单元。消费者数量超过队列数量时,多余实例空转;消费者数量少于队列数量时,单实例承担多个队列。

扩容步骤:

  1. 先确认消费慢原因;
  2. 优化单条处理耗时;
  3. 增加实例;
  4. 增加线程;
  5. 最后考虑扩队列;
  6. 注意顺序消息影响。

30.11 消息积压如何处理?

先分类:

现象 原因
消费组不在线 部署或配置问题
消费耗时高 业务和下游瓶颈
重试风暴 下游异常
热点队列 key 或路由集中

处理顺序:

  1. 保护下游;
  2. 降级非核心逻辑;
  3. 增加有效消费者;
  4. 拆分热点 Topic 或 key;
  5. 评估扩队列;
  6. 恢复后对账。

30.12 如何设计消息幂等?

回答框架:

  1. 选择业务幂等键,如 eventId、paymentId;
  2. 事件表或业务表唯一约束;
  3. 事件处理与业务变更同事务;
  4. 状态机条件更新;
  5. Redis 只做快速拦截;
  6. 针对并发和重放测试;
  7. 用对账兜底。

不要只说“用 Redis setnx”。

30.13 RocketMQ 和 Kafka 怎么选?

RocketMQ 适合业务消息、事务消息、延迟消息、重试死信、大量 Topic 队列和消息轨迹查询。Kafka 适合流日志、实时计算管道、丰富连接器生态和大规模 append-only 回放。

加分项:

  1. 不做绝对化比较;
  2. 提到两者语义差异;
  3. 强调用自身负载压测;
  4. 讨论团队能力和运维成本;
  5. 提混合架构。

30.14 死信队列如何治理?

死信不是删除终点,而是治理队列:

  1. 保存异常、堆栈和上下文;
  2. 告警按未处理年龄和业务影响分级;
  3. 修复代码或数据;
  4. 小批量重放;
  5. 幂等保护;
  6. 记录处理结论;
  7. 沉淀告警规则。

30.15 消息轨迹有什么用?

轨迹能证明:

  1. 生产端是否发送成功;
  2. 消息何时写入 Broker;
  3. 进入哪个队列和位点;
  4. 哪个消费组拉取;
  5. 消费耗时和结果;
  6. 是否重试或死信。

限制:需要开启、有开销、可能采样,敏感信息要脱敏。

30.16 项目中如何做容量规划?

回答公式:

disk = peak bytes/s × retention × replica × expansion
queues = required consumer parallelism
network = send + replicate + consume + trace

再补充峰值、重试、死信、轨迹、消费 lag、故障恢复窗口、多租户隔离和压测修正。

30.17 高频追问清单

  1. 半消息回查失败怎么办?
  2. 顺序消息消费失败能否跳过?
  3. 广播模式和集群模式区别?
  4. Tag 过滤和 SQL 过滤区别?
  5. Proxy 模式解决什么问题?
  6. Controller 如何防止脑裂?
  7. 磁盘满了怎么办?
  8. 位点重置有什么风险?
  9. 迁移集群时位点怎么处理?
  10. 如何验证消息没有丢?

回答策略:先讲业务目标,再讲机制,最后讲监控、演练和回滚。

本章小结

RocketMQ 面试的高频考点集中在消息语义、存储结构、事务、顺序、延迟、重试幂等、高可用和容量治理。高质量回答要区分“机制”和“生产实践”,明确版本差异和故障边界,并能给出可验证的监控与对账方案。

思考题

  1. 如何用一句话说清事务消息的边界?
  2. 顺序消息为什么容易牺牲吞吐?
  3. 为什么“不丢”必须分层讨论?
  4. 死信治理需要哪些字段?
  5. 面试中如何展示生产经验?