RocketMQ 的架构是怎么样的?

一则或许对你有用的小广告

欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于 Spring AI + Spring Boot3.x + JDK 21...点击查看;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot3.x + JDK 17...点击查看项目介绍; 演示链接: http://116.62.199.48:7070/;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/

面试考察点

  1. 全局架构认知:面试官不仅仅是想知道 RocketMQ 有几个组件,更是想知道你是否理解各组件的职责边界和协作关系,能否从宏观角度把握整个消息系统的设计。

  2. 设计思想理解:考察你是否理解 RocketMQ 为什么这么设计——比如为什么用 NameServer 而不是 ZooKeeper、为什么 Broker 要分 Master/Slave、Topic 和 Queue 的关系是什么。懂 "为什么" 比 "是什么" 更重要。

  3. 高可用感知:架构设计的核心目标之一是高可用,面试官想看你是否知道 RocketMQ 是如何通过架构保证高可用的(主从切换、消息重试、故障隔离等)。

核心答案

RocketMQ 的整体架构由 四大核心组件 构成,采用去中心化的设计理念:

组件角色类比核心职责
NameServer路由注册与发现注册中心管理 Broker 路由信息,无状态,互相独立
Broker消息存储与转发消息服务器接收、存储、投递消息,分 Master/Slave
Producer消息发送者寄件人发送消息,支持多种发送方式
Consumer消息消费者收件人拉取/推送消息,支持集群/广播消费

一句话总结:Producer 和 Consumer 通过 NameServer 发现 Broker 地址,Broker 负责消息的存储和转发,NameServer 各节点独立、无状态,整体架构去中心化、高可用。

深度解析

一、整体架构全景图

上图展示了 RocketMQ 的完整架构,整体分为以下几层:

  • 接入层Producer 负责发送消息,Consumer 负责消费消息,它们都是客户端。
  • 路由层NameServer 集群充当路由注册中心,每个节点独立运行,互不通信,无状态设计。
  • 存储层Broker 集群负责消息的存储和转发,每个 BrokerMaster(主)和 Slave(从),通过同步/异步复制保证数据可靠性。

消息流转路径:ProducerNameServer(获取路由)→ Master Broker(存储消息)→ Consumer(拉取消费)。

二、四大组件深度剖析

1. NameServer——轻量级注册中心

// NameServer 核心数据结构(源码简化)
public class RouteInfoManager {
    // Topic → QueueData 的映射(一个 Topic 分布在哪些 Broker 上)
    HashMap<String/* topic */, Map<String /* brokerName */, QueueData>> topicQueueTable;

    // Broker 地址信息
    HashMap<String/* brokerName */, BrokerData> brokerAddrTable;

    // Broker 存活信息(心跳检测)
    HashMap<String/* brokerAddr */, BrokerLiveInfo> brokerLiveTable;
}

NameServer 的核心特点

  • 无状态:各 NameServer 节点之间互不通信,不需要选举,不存在集群一致性问题
  • 轻量级:不需要 ZooKeeper 那样的 Paxos/Raft 共识算法,启动快、资源占用少
  • 心跳机制:Broker 每 30 秒向所有 NameServer 发送心跳,NameServer 超过 120 秒未收到心跳则剔除该 Broker
  • AP 模型:追求可用性(Availability)而非强一致性,Broker 可能短暂向不同 NameServer 注册了不同状态

为什么不用 ZooKeeper?

对比维度NameServerZooKeeper
设计理念极简,只做路由通用协调服务
一致性协议无(各自独立)ZAB 协议
性能极高受限于 Leader 选举
运维复杂度高(需要集群选举)
适用场景消息路由发现分布式锁、配置管理

核心原因:RocketMQ 的路由信息天然具有最终一致性的特点——Producer 发消息时即使拿到略微过期的路由,大不了发一次失败,重试即可。不需要 ZooKeeper 那样的强一致性保证,所以选择了更轻量的自研 NameServer。

2. Broker——消息存储服务器

上图展示了 Broker 内部的核心存储结构,关键设计如下:

  • CommitLog:所有 Topic 的消息混合顺序写入同一个物理文件。这是 RocketMQ 高吞吐的关键——顺序写磁盘的性能接近内存写,随机写磁盘则慢几个数量级。一个 Broker 实例只有一个 CommitLog
  • ConsumeQueue:消息的逻辑队列,相当于 CommitLog 的索引。每条记录固定 20 字节(8 字节 offset + 4 字节 size + 8 字节 tag hash),指向 CommitLog 中真实消息的物理位置。Consumer 先读 ConsumeQueue 定位消息,再去 CommitLog 取消息体。
  • IndexFile:可选的消息索引文件,支持按消息 Key 和时间范围快速查询。

为什么 CommitLog 要混合存储?

顺序写是磁盘 I/O 的最高性能模式。如果把每个 Topic 单独一个文件,就会有多个文件的随机写,性能急剧下降。混合写入后,所有消息追加到同一个文件,磁盘顺序写 TPS 可达 10 万+。

Master 与 Slave 的关系

维度MasterSlave
角色主节点,负责读写从节点,只读备份
编号brokerId = 0brokerId > 0
数据来源接收 Producer 消息从 Master 同步复制
消费Consumer 可从 Master 拉取Consumer 可从 Slave 拉取(Master 压力大时分担读负载)
故障处理宕机后 Slave 可接管(Dledger 模式自动选举)

3. Producer——消息发送者

上图展示了 Producer 发送消息的完整流程:

  • 步骤一(路由获取):Producer 启动时连接 NameServer,获取指定 Topic 的路由信息(即该 Topic 分布在哪些 Broker 的哪些 Queue 上)。
  • 步骤二(Queue 选择):根据发送策略选择目标 MessageQueue。普通消息轮询分发到不同 Queue,保证负载均衡;顺序消息根据 Key hash 到固定 Queue
  • 步骤三(发送消息):与 Master Broker 建立 TCP 长连接(Netty),发送消息。
  • 步骤四(失败重试):发送失败默认重试 2 次,且重试时会避开上次失败的 Broker,提高成功率。
  • 步骤五(路由更新):Producer 本地缓存路由信息,定期从 NameServer 更新,感知 Broker 上下线变化。

4. Consumer——消息消费者

上图展示了 Consumer 的两种消费模式:

  • 集群消费(Clustering):同一个 Consumer Group 下的多个 Consumer 分摊消费 Queue,每条消息只会被 Group 中的一个 Consumer 消费。这是默认模式,适用于大部分业务场景(如订单处理)。Consumer 数量不要超过 Queue 数量,否则多余的 Consumer 会空闲。
  • 广播消费(Broadcasting):每条消息会被 Group 中的所有 Consumer 都消费一遍。适用于缓存刷新、配置广播等需要 "全量通知" 的场景。

三、一条消息的完整生命周期

上图展示了一条消息从发送到消费的完整生命周期,共 8 个阶段:

  • 阶段一(①②③):Producer 查询 NameServer 获取路由,选择目标 Queue,将消息发送到 Master Broker。
  • 阶段二(④⑤):Broker 将消息顺序写入 CommitLog,根据刷盘策略(同步/异步)持久化,并根据复制策略(同步/异步)同步到 Slave。同时异步构建 ConsumeQueue 索引。
  • 阶段三(⑥⑦⑧):Consumer 从 NameServer 获取路由后,与 Broker 建立长连接拉取消息。处理成功则更新消费进度;失败则进入重试机制,最多重试 16 次,仍未成功则进入死信队列(DLQ)。

四、Topic 与 MessageQueue 的关系

上图展示了 Topic 与 MessageQueue 的关系:

  • Topic 是逻辑上的消息主题,比如 "订单 Topic"。
  • MessageQueue(Queue) 是 Topic 的物理分片,是消息存储和并发消费的最小单位
  • 一个 Topic 可以有多个 Queue,分布在不同 Broker 上,实现分布式存储和并行消费
  • Queue 数量决定了最大并发消费能力——Consumer 数量超过 Queue 数量后,多余的 Consumer 将无法分配到 Queue,处于空闲状态。

面试高频追问

  1. 追问一:NameServer 挂了一台怎么办?

    • 不影响。各 NameServer 节点独立运行,Producer/Consumer/Broker 同时连接所有 NameServer。挂掉一台后,客户端自动切换到其他存活的 NameServer 节点。
  2. 追问二:Broker 的 Master 挂了怎么办?

    • Slave 可以继续提供消息消费(只读),但不能接收新消息。配合 Dledger 组件或 Controller 模式(5.0),可以实现 Slave 自动晋升为 Master,完成故障自动切换。
  3. 追问三:为什么 RocketMQ 用 NameServer 而不是 ZooKeeper?

    • 路由信息天然适合最终一致性,不需要 ZK 的强一致性;NameServer 无状态、无选举,性能更高、运维更简单;阿里实践表明 ZK 在大规模 Topic 场景下性能瓶颈明显。
  4. 追问四:CommitLog 和 ConsumeQueue 是什么关系?

    • CommitLog 存储所有消息的完整内容(物理存储),一个 Broker 只有一个;ConsumeQueueCommitLog 的逻辑索引,按 Topic + QueueId 组织,Consumer 通过它快速定位消息。

常见面试变体

  • 变体一:"介绍一下 RocketMQ 的整体架构设计"
  • 变体二:"RocketMQ 有哪些核心组件?各自的作用是什么?"
  • 变体三:"RocketMQ 的 NameServer 和 ZooKeeper 有什么区别?"
  • 变体四:"RocketMQ 的 Broker 是怎么存储消息的?"

记忆口诀

四大组件:Name(路由)、Broker(存储)、Producer(发)、Consumer(收)。

存储模型:CommitLog(一锅炖)→ ConsumeQueue(分盘索引)→ IndexFile(按 Key 查)。

设计哲学:顺序写提升吞吐,混合存减少随机 I/O,去中心化提升可用性。

总结

RocketMQ 架构由 NameServer(路由)、Broker(存储)、Producer(发送)、Consumer(消费) 四大组件构成。核心设计亮点有三:一是采用轻量级 NameServer 替代 ZooKeeper,去中心化、无状态、高可用;二是 Broker 内部通过 CommitLog 顺序写 + ConsumeQueue 异步索引实现高吞吐存储;三是 Master/Slave 主从复制保证消息可靠性。面试时建议从四大组件入手,再展开存储模型和高可用机制,展现对架构设计的深度理解。