RocketMQ 5.x 扩缩容方案
引言
随着云原生技术的普及,越来越多的企业将消息队列部署在容器化环境中。RocketMQ 作为一款高性能的消息中间件,在云原生环境下的扩缩容能力成为了一个关键需求。然而,与无状态应用的扩缩容不同,RocketMQ 作为有状态服务,其扩缩容面临着独特的挑战。本文将深入探讨 RocketMQ 5.x 在云原生环境下的扩缩容方案,分析扩缩容过程中面临的技术挑战和可行的解决方案。
背景知识:RocketMQ 的基本概念
在深入讨论之前,先简单介绍几个关键概念:
- NameServer:类似于服务注册中心,记录了集群中所有 Broker 的地址信息
- Broker:消息存储节点,负责接收、存储和投递消息
- Queue:消息队列,一个 Topic 可以包含多个 Queue,分布在不同的 Broker 上
- commitLog:Broker 存储消息的文件,采用顺序写入的方式,就像一个只能往后写的笔记本
RocketMQ 是有状态服务,因为消息存储在 Broker 的本地磁盘上,不能随意迁移或删除。
扩缩容面临的挑战
在讨论具体方案之前,我们需要先明确一个核心观点:RocketMQ 扩缩容的本质问题,不是物理节点或容器的扩缩容——这些在云平台上已经有成熟的解决方案。真正的难点在于:如何在扩缩容过程中保障消息数据的一致性、可用性和业务连续性。
扩容相对简单
扩容相对简单,只需要增加主机节点和云盘,创建新的 Broker 实例,将其注册到 NameServer,然后调整路由规则即可。新消息会自动路由到新节点,整个过程对业务透明。
举个例子:原来有 2 台主机,每台运行 1 个 Broker,现在业务增长需要扩容。我们增加 1 台主机,在上面创建新的 Broker,注册到 NameServer,新消息就会自动路由到新的 Broker 上。
缩容就复杂了
但缩容就复杂得多了。如果直接摘除某个 Broker,会带来一系列严重问题:该 Broker 上的消息如何处理?消费者正在消费的消息会怎样?未消费的消息会丢失吗?消息顺序如何保证?事务消息如何处理?
举个例子:原来有 3 台主机,每台运行 1 个 Broker,现在业务量下降需要缩容到 2 台。如果直接关掉第 3 台主机,那么这台主机上存储的消息怎么办?消费者还没消费完的消息会丢失吗?
消息迁移是不可接受的
更关键的是,消息迁移是不可接受的。RocketMQ 的 commitLog 采用顺序写入的方式,数据很难合并,也不能重新写入。这就像一个只能往后写的笔记本,已经写满的内容不能撕下来贴到另一个本子上。
这与数据库的缩容完全不同,数据库可以通过数据迁移和重新分片来实现缩容,但 RocketMQ 的消息存储机制决定了这条路走不通。
因此,我们需要寻找不涉及消息迁移的缩容方案。
方案一:资源缩容,架构不缩
方案思路
方案一的核心思想是:只缩容资源(主机和云盘),不缩容架构(Broker 实例)。
具体场景:原来有 3 台主机(主机A、主机B、主机C),每台运行 1 个 Broker(Broker1、Broker2、Broker3)。现在要缩容到 2 台主机,但仍然保持 3 个 Broker。
扩容阶段
扩容前后架构对比:

扩容时,按照常规流程操作:
- 增加主机节点和云盘
- 在新主机上创建主 Broker
- 将新 Broker 加入集群
- 调整路由规则(如果使用 Proxy 模式,需要在 Proxy 层调整路由,将新 Broker 加入路由列表)
扩容时序图:

缩容阶段
缩容前后架构对比:

缩容时,采用以下步骤:
步骤1:选择要缩容的主机
假设我们要缩容主机C(运行Broker3)。
步骤2:停止Broker3服务
停止主机C上的Broker3服务,此时Broker3不再接收新消息。
步骤3:迁移云盘数据
将主机C上的云盘数据迁移到剩余的主机(比如主机A)。云盘数据迁移是云平台提供的成熟功能,类似于把一个硬盘的数据复制到另一个硬盘。这个过程可能需要几分钟到几小时,取决于数据量。
步骤4:在剩余主机上启动Broker3
在主机A上启动Broker3。Broker3 启动后会自动连接 NameServer 注册,位置变化对集群没有影响。此时主机A上同时运行着Broker1和Broker3。
步骤5:关闭原主机
关闭主机C,释放资源。
业务影响:在步骤2到步骤4期间,Broker3 暂时不可用,会影响写入 Broker3 的消息和从 Broker3 消费的消息。建议在业务低峰期执行。
最终结果:
- 主机数量:3台 → 2台
- Broker数量:3个 → 3个(不变)
- 主机A运行:Broker1 + Broker3
- 主机B运行:Broker2
从架构上看,Broker 数量没有变化,只是资源(主机和云盘)进行了缩容。
缩容时序图

方案优点
- 不涉及消息迁移:commitLog 不需要合并,避免了复杂的数据迁移逻辑
- 路由简单:Broker 数量不变,路由规则无需调整
- 数据完整性有保障:云盘数据迁移是成熟的技术,数据安全性高
- 兼容性好:不依赖特定的路由机制,适用于各种部署模式
方案缺点
- 资源利用率可能不均衡:一个主机运行多个 Broker,可能出现资源竞争
- 运维复杂度增加:需要在单主机上管理多个 Broker 实例
- 扩展性受限:单主机的资源限制了 Broker 的数量
方案二:架构缩容,Proxy 层路由控制
方案思路
方案二的核心思想是:真正实现架构缩容,通过 Proxy 层的路由控制来保障消息消费。
具体场景:原来有 3 台主机(主机A、主机B、主机C),每台运行 1 个 Broker(Broker1、Broker2、Broker3)。现在要缩容到 2 台主机,同时将 Broker 数量也减少到 2 个。
什么是 Proxy?
Proxy 是 RocketMQ 5.x 引入的一个组件,作为统一接入层。客户端(Producer 和 Consumer)不再直接连接 Broker,而是先连接 Proxy,Proxy 再根据路由规则将请求转发到对应的 Broker。
打个比方:Proxy 就像公司的前台,客户(Producer/Consumer)不直接找员工(Broker),而是先找前台,前台根据客户的需求指引到对应的员工。
RocketMQ 5.x 的路由机制变化
方案二依赖于 RocketMQ 5.x 引入的 Proxy 模式。在 RocketMQ 4.x 中,Producer 和 Consumer 直接连接 NameServer,从 NameServer 获取 Topic 路由信息,客户端本地缓存路由信息,并根据负载均衡策略选择 Queue。客户端甚至可以设置特定的 Queue 路由。
RocketMQ 5.x 引入了 Proxy 模式,Proxy 作为统一接入层,客户端连接 Proxy 而不是直接连接 Broker。Proxy 负责路由转发和负载均衡,可以控制 Producer 的消息路由(只写特定 Broker)和 Consumer 的消息消费路由(读特定 Broker)。路由策略集中在 Proxy 层,便于统一管理。
当然,RocketMQ 5.x 仍然支持 4.x 的直连模式,以保证兼容性。但推荐使用 Proxy 模式,以获得更好的路由控制能力。
Proxy 模式下 4.x 直连模式的兼容性
在 Proxy 模式下,需要特别关注 4.x 客户端的兼容性问题。RocketMQ 4.9.7 SDK 为了兼容 5.x 服务,在 SDK 中强制携带 brokerName。这意味着:
问题场景:
- Producer/Consumer 从 NameServer 获取 Topic 路由信息,其中包含 brokerName
- brokerName 是 Producer 和 Consumer 共用的
- 如果直接修改路由规则,会导致缩容节点的消息无法消费
- 例如:原来有 Broker1、Broker2、Broker3,缩容后只剩 Broker1、Broker2,但客户端仍然持有 Broker3 的 brokerName
为什么不能直接修改路由:
- Producer 和 Consumer 共享同一个 brokerName
- 如果直接修改路由,Producer 会将消息写入新的 Broker,但 Consumer 仍然尝试从旧的 Broker 消费
- 这会导致缩容节点的消息无法被消费
Proxy 的解决方案:
在用户缩容状态时,Proxy 对于用户提供的缩容中的 brokerName 自动分配到一个固定的有效 broker 上。具体实现:
- 缩容状态检测:Proxy 检测到某个 Broker 处于缩容状态
- brokerName 映射:Proxy 维护一个映射表,将缩容中的 brokerName 映射到一个固定的有效 broker
- 请求转发:
- Producer 发送消息时,如果携带的是缩容中的 brokerName,Proxy 自动将其转发到映射的有效 broker
- Consumer 拉取消息时,如果携带的是缩容中的 brokerName,Proxy 自动将其转发到映射的有效 broker
- 透明处理:整个过程对客户端透明,客户端无需修改任何代码
示例:
缩容前:
- Broker1 (brokerName: broker-a)
- Broker2 (brokerName: broker-b)
- Broker3 (brokerName: broker-c)
缩容后(Broker3 被移除):
- Broker1 (brokerName: broker-a)
- Broker2 (brokerName: broker-b)
Proxy 映射表:
- broker-c → broker-a (固定映射)
客户端请求:
- Producer 发送消息到 broker-c → Proxy 转发到 broker-a
- Consumer 从 broker-c 拉取消息 → Proxy 转发到 broker-a
这种方案确保了缩容过程中的消息一致性,同时保持了客户端的兼容性。
扩容阶段
扩容前后架构对比:

扩容时,按照常规流程操作:
- 增加主机节点和云盘
- 在新主机上创建主 Broker
- 将新 Broker 加入集群
- 在 Proxy 层调整路由,将新 Broker 加入路由列表,Producer 和 Consumer 开始读写新 Broker
扩容时序图:

缩容阶段
缩容前后架构对比:

缩容时,采用以下步骤:
步骤1:选择要缩容的Broker
假设我们要缩容Broker3(运行在主机C上)。
步骤2:调整Proxy路由
在 Proxy 层调整路由规则:
切换前的连接方式:
- Producer → Proxy → Broker1/Broker2/Broker3(所有Broker)
- Consumer → Proxy → Broker1/Broker2/Broker3(所有Broker)
切换后的连接方式:
- Producer → Proxy → Broker1/Broker2(不再写Broker3)
- Consumer → Proxy → Broker1/Broker2/Broker3(仍然读Broker3)
路由逻辑:Proxy 根据配置的路由规则,将 Producer 的请求只转发到 Broker1 和 Broker2,将 Consumer 的请求转发到所有 Broker(包括 Broker3)。客户端无需修改,因为客户端连接的都是 Proxy。
步骤3:等待消息消费完毕
Consumer 继续从 Broker3 读取消息,直到 Broker3 上的所有消息都被消费完毕。可以通过监控消费进度来判断,如果消息超过配置的超时时间仍未消费,可以直接丢弃。这个过程可能需要数小时甚至数天,取决于消息积压情况。
步骤4:移除Broker
确认 Broker3 上的消息都已消费完毕后,从集群中移除 Broker3,关闭主机C。
业务影响:整个缩容过程对业务无影响,Producer 和 Consumer 都能正常工作。
最终结果:
- 主机数量:3台 → 2台
- Broker数量:3个 → 2个
- 主机A运行:Broker1
- 主机B运行:Broker2
缩容时序图

方案优点
- 真正的架构缩容:Broker 数量真正减少,资源利用率更优
- 资源均衡性好:避免了单主机运行多个 Broker 的资源竞争
- 扩展性强:不受单主机资源限制
方案缺点
- 缩容周期较长:需要等待消息消费完毕,可能需要数小时甚至数天
- 实现复杂度高:需要 Proxy 路由配置、消息消费状态监控等
- 依赖 Proxy 模式:需要使用 RocketMQ 5.x 的 Proxy 模式
- 兼容性问题:需要考虑 4.x 客户端的兼容性
方案对比
技术复杂度对比
方案一:技术复杂度中等,主要需要云盘迁移技术和单主机多 Broker 的配置经验。实施时间约 1-2 小时(不含云盘迁移时间),风险较低。
方案二:技术复杂度较高,需要 Proxy 路由配置、消息消费状态监控、Broker 移除时机判断等多项技术。实施时间可能需要 1-3 天(取决于消息消费速度),风险中等。
业务影响对比
方案一:在 Broker 停止和迁移期间有短暂的业务影响,建议在业务低峰期执行。
方案二:整个缩容过程对业务无影响,Producer 和 Consumer 都能正常工作。
适用场景
方案一适用于:
- 对缩容速度要求不高的场景
- 资源成本敏感,但运维成本可接受的场景
- Broker 数量较少的场景(避免单主机资源竞争严重)
- 希望保持架构稳定的场景
- 技术团队对 RocketMQ 有一定了解,但不想引入复杂组件
- 可以接受短暂业务中断的场景
方案二适用于:
- 对资源利用率要求高的场景
- Broker 数量较多,需要真正架构缩容的场景
- 可以接受较长缩容周期的场景
- 已使用或计划使用 Proxy 模式的场景
- 技术团队有能力维护复杂的路由配置
- 对业务连续性要求极高的场景
总结
RocketMQ 5.x 在云原生环境下的扩缩容是一个复杂但重要的问题。本文分析了两种可行的缩容方案:资源缩容(架构不缩)和架构缩容(Proxy 路由控制)。
方案一(资源缩容,架构不缩)技术实现相对简单,风险可控,适合大多数场景。方案二(架构缩容,Proxy 路由控制)能够实现真正的架构缩容且无业务影响,但实现复杂度高,适合对资源利用率要求极高的场景。
在实际应用中,需要根据业务需求、技术团队能力和资源成本等因素综合考虑,选择最适合的方案。