引言
Apache RocketMQ 社区新发布的 5.x 版本是其云原生架构演进的重要里程碑,其中包括两项重大更新:
- 实现了存储与计算的解耦,进一步提升了系统的可扩展性和云原生适配能力。
- 引入了 POP 消费模式,将负载均衡逻辑从客户端迁移到了 Broker 端。
为适配这些新特性,开源社区推出了全新的基于 gRPC 协议的轻量化客户端。不过,现有的仍通过 Remoting 协议接入的用户,如果不更新代码并替换客户端 SDK,就无法享受到这些新能力。

为了解决这个问题,腾讯云消息队列 RocketMQ 版通过基于虚拟队列的兼容性增强方案,实现了对 Remoting 协议客户端的完整支持,使现有用户在无需修改代码的情况下也能平滑使用 5.x 版本。 本文将从整体架构、关键设计思路以及核心能力等方面详细介绍腾讯云虚拟队列方案。
RocketMQ 5.x 版本对 Remoting 客户端的限制
SDK 版本依赖
在 RocketMQ 4.x 架构中,客户端与后端 Broker 之间采用直连模式,即每个客户端与队列路由表中的所有 Broker 建立长连接。而在 5.x 版本升级为存算分离架构后,通信方式变更为转发模式:Proxy 负责接收客户端的连接请求,并将其转发到相应的 Broker。与直连模式相比,转发模式简化了客户端侧的逻辑,同时避免了多网络环境下复杂的网络打通问题。
为了适配 5.x 架构,Remoting SDK 在 v4.9.5 版本中对协议进行了扩展,增加了 Broker Name 字段,Proxy 通过该字段获取客户端请求的目标 Broker 身份。
因此,Remoting 客户端用户接入 RocketMQ 5.x 的前提是将 SDK 升级至 v4.9.5 或更高版本。

然而,升级 SDK 版本对现有业务来说是一个挑战,它不仅要求进行额外的测试验证以确保兼容性与稳定性,而且对于那些场景复杂、上下游链路交织的业务团队来说,梳理和推动版本升级的整个周期可能会相当漫长。更值得关注的是,使用较低版本 Remoting 客户端在 RocketMQ 用户中仍是主流,以腾讯云消息队列 RocketMQ 版的数据来看,超过 90% 的用户在使用版本低于 v4.9.5 的 Remoting 客户端。

消费者绑定队列
在 RocketMQ 4.x 架构中,消费者采用 PULL 模式进行消费:SDK 周期性地获取全量队列和全量消费者,并根据既定算法算出队列与消费者的分配绑定关系,然后轮询拉取分配给自己的队列。
这种基于队列粒度的负载均衡机制有一个核心痛点:一旦某个消费者实例由于单机问题导致消费能力下降,绑定到该消费者上的所有队列都会被阻塞,而其他正常的消费者实例即使处于空闲状态也无法介入接管。

为此,RocketMQ 5.x 引入了 POP 消费模式,将负载均衡和队列位点管理等逻辑从客户端迁移到了服务端,并在全新推出的基于 gRPC 协议的轻量化 SDK 中对 POP 模式做了适配,实现了消息粒度的消费负载均衡。Remoting 客户端由于采用的是 PULL 模式,接入 RocketMQ 5.x 后仍然是消费者绑定队列的均衡机制。

腾讯云虚拟队列方案
为了解决 RocketMQ 5.x 对 Remoting 客户端的限制,腾讯云消息队列 RocketMQ 版提出了虚拟队列方案,核心能力包括:
- 服务端层面主动兼容低版本 Remoting 客户端,大幅降低现有业务平滑过渡到 RocketMQ 5.x 的成本和风险。
- 将适配 POP 消费模式的逻辑上移到了服务端,使得 Remoting 客户端也能实现消息粒度的消费负载均衡。
虚拟队列方案的核心思想是在客户端和 Broker 之间建立一层抽象,然后在抽象层实现 Remoting 协议的向下兼容和消费模式的透明转换。

虚拟队列定义
RocketMQ 中的一个主题由分布在多个 Broker 上的多个队列组成,客户端通过路由查询接口获取主题的队列列表来进行消息收发。虚拟队列指的是将返回给客户端的队列虚拟化,即存储层真实队列不再对客户端可见。
如下图所示,主题在 Broker-0、 Broker-1 和 Broker-2 上各有 N 个队列,而 Remoting 客户端查询到的是 vBroker 上 M 个队列。虚拟化后的队列与真实队列的映射关系由服务端管理,因此 Remoting 客户端无需在请求中标识目标 Broker 身份,即解除了 5.x 对 Remoting SDK 版本的依赖。

消费模式透明转换
服务端通过将 Remoting 客户端的 PULL 模式无感转换为 POP 模式来实现消息粒度的消费负载均衡。
Remoting 消费者与服务端的交互主要包括两部分:
-
通过虚拟队列向服务端发送 PULL 请求,拉取队列中待消费的消息。
-
消费完成后向服务端提交虚拟队列消费位点,采用累积确认的定时同步机制。
首先,服务端会将 Remoting 客户端对虚拟队列的 PULL 请求转换为对存储层真实队列的 POP 请求。请求转换过程中的队列映射关系由队列选择器决策,并且支持动态调整策略,这样能够做到在保证消息时延的前提下尽可能降低 POP 轮询对 Broker 的负载压力。
此外,服务端还会为每个客户端虚拟队列维护一个内存队列,以适配 POP 模式的不可见时间机制和选择确认机制:
-
将 Remoting 客户端对 Offset 的累积确认转换为对 POP ReceiptHandle 的选择确认。
-
自动续期已拉取未确认消息的不可见时间,直至客户端确认或消费超时。
消费模式转换在服务端计算层 Proxy 上实现,对 Remoting 客户端和存储层 Broker 而言是完全透明、无感知的。整个过程不依赖任何持久化的状态数据,对 Proxy 的部署架构和水平扩展性没有任何影响。

消除客户端重平衡
当 Remoting 客户端检测到消费组发生变化(队列数量变化、消费者列表变化)时会执行重平衡(Rebalance)过程:重新计算队列分配结果 -> 转移队列消费所有权。
在大规模集群或频繁部署的业务场景中,消费者的上下线会导致 Rebalance 频繁触发,对系统稳定性有不可忽视的影响。实际上,开启虚拟队列后,真实队列的数量变化已经对客户端屏蔽了,而且也不再需要客户端侧的 Rebalance 机制了,因为消费的负载均衡完全由服务端控制。
于是,腾讯云消息队列 RocketMQ 版通过精准控制消费者列表查询接口的响应实现了 Remoting 消费者之间的相互不可见,即屏蔽了消费者列表变化,从而完全消除了客户端重平衡,显著提高了系统稳定性。

队列顺序消费
RocketMQ 支持队列顺序消费以满足部分业务场景。开启虚拟队列后,Remoting 客户端顺序消费由两部分保证:
- 服务端计算层负责将队列分配给在线客户端,并且确保每个队列的消息只会被一个客户端拉取。
- Remoting SDK 拉取到消息后,负责将消息有序地、串行地投递给业务消费。

结语
本文系统阐述了 Apache RocketMQ 5.x 在存算分离架构与 POP 消费模式下的演进,并重点分析了 Remoting 协议客户端面临的两大兼容性挑战:SDK 版本依赖以及消费者队列绑定机制的限制。
针对上述挑战,腾讯云消息队列 RocketMQ 版提出了虚拟队列兼容方案,通过队列虚拟化和消费模式的无感切换,实现了对 Remoting 协议客户端的完整支持,为大规模存量用户快速获取新架构带来的技术红利提供了高效路径。