RocketMQ架构精讲:NameServer、Broker、Producer、Consumer核心流程

0 阅读9分钟

在这里插入图片描述

RocketMQ架构精讲:NameServer、Broker、Producer、Consumer核心流程

作者:黒漂技术佬 系列专栏:RocketMQ核心原理与无人售货柜项目实战

一、先看全景:RocketMQ整体架构

把RocketMQ的架构想象成一个快递物流网络,有四个核心角色:

                    ┌─────────────────┐
                    │   NameServer    │  ← 注册中心(物流信息中心)
                    │  (路由信息存储)  │
                    └────────┬────────┘
                             │ 心跳注册/路由查询
              ┌──────────────┼──────────────┐
              │              │              │
        ┌─────▼─────┐  ┌─────▼─────┐  ┌────▼──────┐
        │  Broker-A  │  │  Broker-B  │  │  Broker-C  │  ← 消息存储服务器(快递分拣中心)
        │ (Master)   │  │ (Master)   │  │ (Master)   │
        │ (Slave)    │  │ (Slave)    │  │ (Slave)    │
        └─────┬─────┘  └─────┬─────┘  └────┬──────┘
              │              │              │
              │  发送消息     │              │
        ┌─────┴──────────────┴──────────────┴─────┐
        │              Producer                    │  ← 消息生产者(寄件人)
        │         (订单服务/支付服务/...)           │
        └──────────────────────────────────────────┘

        ┌──────────────────────────────────────────┐
        │              Consumer                    │  ← 消息消费者(收件人)
        │       (库存服务/推送服务/告警服务)         │
        └──────────────────────────────────────────┘
              │              │              │
              └──────────────┼──────────────┘
                             │ 拉取消息
                    ┌────────▼────────┐
                    │    Broker       │
                    └─────────────────┘

四个角色的分工一句话概括:

  • NameServer:路由信息中心,告诉Producer消息该往哪发,告诉Consumer消息该从哪取
  • Broker:消息存储服务器,真正存消息和转发消息的地方
  • Producer:消息生产者,发消息的
  • Consumer:消息消费者,收消息的

下面逐个拆解。

二、NameServer:轻量级注册中心

2.1 它是干什么的

NameServer是RocketMQ的"通讯录"。Broker启动时把自己的地址、Topic信息、队列信息注册到NameServer;Producer和Consumer启动时从NameServer拉取这份路由表,才知道消息往哪发、从哪取。

2.2 为什么不用Zookeeper

很多中间件(Kafka、Dubbo)用Zookeeper做注册中心,RocketMQ早期版本也用过,后来自己搞了个NameServer,原因是一个经典的分布式理论取舍:AP vs CP

先解释下CAP定理的三个字母:

  • C(Consistency)一致性:所有节点看到的数据是一致的
  • A(Availability)可用性:每个请求都能收到响应(不保证是最新数据)
  • P(Partition tolerance)分区容错:网络分区时系统仍能运行

分布式系统三者只能选其二,由于网络分区(P)不可避免,实际选择是CP还是AP。

对比项Zookeeper (CP)NameServer (AP)
一致性强一致最终一致
可用性写入需多数派投票,leader选举期间不可用各节点独立,互不通信
复杂度高(ZAB协议、leader选举)低(就是个内存HashMap)
部署至少3节点集群可单节点,也可多节点互不关联

RocketMQ的选择逻辑:在消息中间件场景里,可用性比强一致更重要。Broker挂了NameServer感知到就行,不追求所有NameServer瞬间数据一致。每个NameServer节点独立维护路由表,Producer/Consumer连任意一个都能拿到数据,偶尔短暂不一致在业务上可接受(Broker心跳30秒上报一次,最多30秒感知到变化)。

2.3 心跳机制

Broker每隔30秒向所有NameServer发心跳,NameServer收到后更新Broker的存活时间戳。NameServer每隔10秒扫描一次路由表,如果发现某个Broker超过120秒没心跳,就判定它下线,从路由表里移除。

这套机制简单粗暴但有效:不搞复杂的一致性协议,用心跳+超时来维护状态。

三、Broker:消息存储和转发服务器

3.1 Master/Slave架构

Broker分Master和Slave两种角色:

  • Master Broker:负责读写,Producer发消息到Master,Consumer也从Master拉消息(默认)
  • Slave Broker:只负责备份,从Master同步数据,Master挂了可接管读请求

同步方式有两种:

异步复制(ASYNC_MASTER):Master收到消息后立即返回成功,然后异步复制给Slave。优点是延迟低,缺点是Master挂了可能丢少量未复制的数据。

同步双写(SYNC_MASTER):Master收到消息后,等Slave也写入成功才返回。优点是数据不丢,缺点是延迟略高。

售货柜场景怎么选?支付相关消息用同步双写保数据安全,日志类消息用异步复制换性能。

3.2 Broker的存储结构

Broker存消息不是随便往磁盘一堆,而是有精心的设计:

CommitLog(统一存储文件)
  ├── 所有Topic的消息混在一起,按写入顺序追加
  ├── 每个文件固定1GB,写满新建
  └── 顺序写磁盘,性能接近内存写

ConsumeQueue(消费队列/逻辑索引)
  ├── 每个Topic的每个Queue对应一个ConsumeQueue文件
  ├── 存储的是消息在CommitLog中的偏移量(offset)、大小、Tag的hashcode
  └── Consumer通过ConsumeQueue快速定位消息

IndexFile(索引文件)
  └── 支持按MessageId和Key查询消息

这个设计的精妙之处在于:写入时所有消息追加到同一个CommitLog,顺序写性能极高;读取时通过ConsumeQueue索引快速定位,读取效率也不低。写入和读取两不误。

3.3 Broker注册到NameServer

Broker启动时把自己的信息打包发给所有NameServer,注册信息包括:

  • Broker名称(brokerName)
  • Broker地址(IP:Port)
  • 集群名称(clusterName)
  • Master/Slave角色标识
  • 该Broker上所有的Topic和Queue信息

注册后每30秒心跳续约,心跳时也会带上最新的Topic路由信息。

四、Producer:消息生产者

4.1 启动流程

Producer启动时做三件事:

  1. 从NameServer拉取路由信息(哪些Broker有哪些Topic的哪些Queue)
  2. 建立到目标Broker的网络连接(Netty长连接)
  3. 启动定时任务,每30秒从NameServer更新路由信息

路由信息缓存在本地,发消息时不用每次都问NameServer,30秒更新一次够用了。

4.2 消息发送流程

Producer发送一条消息的完整流程:

1. Producer校验消息(Topic、Body非空等)
2. 查找Topic的路由信息(本地缓存)
3. 选择目标Queue(负载均衡策略)
   ├── 轮询(默认):Round Robin
   ├── 故障隔离:上次发送失败的Queue暂时排除
   └── 指定Queue:MessageQueueSelector自定义
4. 构建请求,通过网络发送给目标Broker
5. 等待Broker返回确认(根据发送方式决定是否阻塞)
   ├── 同步发送:阻塞等待ACK
   ├── 异步发送:不阻塞,回调通知结果
   └── 单向发送:直接返回不等
6. 根据结果做后续处理(重试/记录日志等)

售货柜场景举例:关门后发送"订单创建"消息,用同步发送确保消息不丢;发送"用户行为日志"用单向发送,丢了也无所谓。

4.3 发送失败重试

Producer发送失败时会自动重试,默认重试2次(共3次尝试)。重试时会避开上次失败的Broker,选择其他Broker的Queue发送。这个机制配合Broker的Master/Slave架构,能在单节点故障时自动切换,对用户透明。

五、Consumer:消息消费者

5.1 两种消费模式

集群消费(Clustering):同一个ConsumerGroup下的多个Consumer实例分摊消费所有消息。比如100条消息,2个Consumer各消费50条。这是最常用的模式,适合横向扩展消费能力。

ConsumerGroup-A (集群模式)
  ├── Consumer-1 ← 消费 Queue-0, Queue-1
  ├── Consumer-2 ← 消费 Queue-2, Queue-3
  └── Consumer-3 ← (如果只有4个Queue,这个会空闲)

广播消费(Broadcasting):同一个ConsumerGroup下的每个Consumer实例都消费全量消息。比如100条消息,2个Consumer各消费100条。适合所有节点都要感知同一份数据的场景,比如本地缓存刷新。

售货柜场景:库存扣减用集群消费(一台柜子的消息只需一个消费者处理),设备配置全量下发用广播消费(所有柜子都要收到配置更新)。

5.2 ConsumerGroup的概念

ConsumerGroup是逻辑上的一组消费者实例,同一个Group必须消费同一个Topic,且消费逻辑必须一致。你可以把它理解为"一个消费团队",团队里的人分工干活(集群模式)或者各自干全部活(广播模式)。

一个典型的微服务部署:库存服务部署3个实例,都配置同一个ConsumerGroup inventory_consumer_group,3个实例自动分摊消费库存Topic的消息。某个实例挂了,Rebalance机制会自动把它负责的Queue分配给其他实例,消费不中断。

5.3 消费者拉取机制

RocketMQ的Consumer本质上是Pull模式——消费者主动从Broker拉取消息,不是Broker推过来的。

但用起来感觉像Push(DefaultPushConsumer),因为它内部用长轮询做了封装:

Consumer向Broker发拉取请求
  ├── Broker有消息 → 立即返回
  └── Broker没消息 → Hold住请求,挂起5秒(默认)
      ├── 5秒内有新消息 → 立即返回
      └── 5秒后还没消息 → 返回空,Consumer再次发起拉取

长轮询的好处:既避免了Push模式下Consumer处理不过来被压垮,又避免了Pull模式下频繁空轮询浪费资源。

六、消息流转全链路

把上面四个角色串起来,一条消息从产生到消费的完整链路:

1. Producer启动 → 从NameServer获取Topic路由信息
2. Producer发送消息 → 根据路由选择Queue → 发送到对应Broker
3. Broker收到消息 → 写入CommitLog → 构建ConsumeQueue索引 → 返回ACK
4. Consumer启动 → 从NameServer获取Topic路由信息
5. Consumer向Broker发拉取请求 → 通过ConsumeQueue定位消息 → 从CommitLog读取
6. Consumer处理消息 → 返回消费状态(CONSUME_SUCCESS/RECONSUME_LATER)
7. 消费失败 → Broker按延迟等级重新投递 → 超过重试上限进入死信队列

七、结合售货柜场景的角色映射

把架构映射到我们的无人售货柜项目:

RocketMQ角色售货柜项目对应具体说明
NameServer部署在总部机房所有服务都连总部NameServer获取路由
Broker-A总部主Broker存储订单、支付、库存等核心消息
Broker-B区域分中心Broker按区域分Topic,减少跨地域网络延迟
Producer订单服务、支付服务、柜子网关各业务服务发消息到Broker
Consumer库存服务、推送服务、告警服务、ERP同步服务各服务消费各自Topic

比如一个完整的支付流程:

  1. 用户关门 → 订单服务(Producer)发送"订单创建"消息到Broker
  2. 库存服务(Consumer)消费消息扣减本地库存
  3. 用户支付完成 → 支付服务(Producer)发送"支付成功"消息
  4. 柜子网关(Consumer)消费消息,通知对应柜子出货
  5. ERP同步服务(Consumer)消费同一消息,更新总部库存
  6. 推送服务(Consumer)消费同一消息,给用户发扣款通知

一条支付消息被4个消费者服务各自消费(不同ConsumerGroup),各司其职,互不干扰。这就是解耦的威力——支付服务只管发消息,谁来消费、怎么消费,它一概不关心。

八、小结

这一篇我们拆解了RocketMQ的四大核心组件:NameServer作为轻量级AP注册中心,Broker负责消息存储和转发(Master/Slave架构+CommitLog/ConsumeQueue存储设计),Producer和Consumer通过长轮询完成消息的发送和拉取。最后把这些角色映射到无人售货柜项目的实际部署中。

下一篇我们动手实操,搭建RocketMQ开发环境。