RocketMQ 5.0:无状态代理模式的探索与实践

本文涉及的产品
性能测试 PTS,5000VUM额度
应用实时监控服务-应用监控,每月50GB免费额度
云原生网关 MSE Higress,422元/月
简介: 未来,我们期望RocketMQ底层的Broker和NameServer 更多聚焦在存储的特性上,比如业务型消息存储的事务、定时、顺序等,快速构建消息索引、打造一致性多副本提升消息可靠性、多级存储来达到更大的存储空间等。

1.jpeg

本文作者:金吉祥, Apache RocketMQ PMC Member,阿里云智能高级技术专家


背景


2.jpeg


首先,让我们来看下是遇到了哪些痛点问题,促使我们去探索一种无状态代理的RocketMQ新架构的;


RocketMQ 拥有一套极简的架构,多语言客户端通过自定义的 Remoting 协议与后端 NameServer 和 Broker建立 TCP 长连接,然后进行消息的路由发现以及完整的消息收发。这套架构的优势是:架构极简,客户端 与 Broker 通过 TCP 直连的模式,拥有较高的性能以及较低的延迟。同时,这套架构采取的是队列模型,非常适合基于队列批量高速拉取消息的场景。


同时,RocketMQ 在上云过程中面临了各种各样的挑战。


首先,云上用户需要更为丰富的业务语义消息,包括事务、定时、顺序以及死信等。为了满足用户的业务侧需求,需要在原先架构的客户端侧和 Broker侧分别进行开发,用户必须升级客户端之后才能享受新功能。


其次,上云过程需要面对更为复杂的网络环境,不同场景下需要不同类型网络的接入。有些用户为了便捷性,期望能够交付公网的接入点,让不同地域的消费者、发送者都能连接到同一个消息服务;而另一种用户为了安全性,需要内网接入点来隔离一些非法的网络请求;RocketMQ原先的架构在应对多网络类型的接入诉求时,成本是比较高的,多网络类型的接入必须同时覆盖NameServer和Broker的每一台机器才行。比如我们需要对内部 Broker进行扩容场景下,如果原先的 Broker 拥有多种类型的网络接入诉求,那么新扩容的 Broker也需要额外绑定上多种类型的网络接入点之后才能正常对外交付。


做下总结,面对上云的挑战,此前的架构逐渐暴露出了如下诸多痛点:

① 富客户端形态:客户端包含了大量企业级特性。用户必须升级客户端才能享受新功能,过程十分漫长。且同样的功能交付必须在多个多语言版本里都进行适配才能满足多语言客户端的接入,工作量巨大。

② 客户端与Broker所有节点的直连模式满足多类型网络接入的成本较高。

③ 按照队列进行负载均衡和消息拉取,后端扩缩容时会触发客户端rebalance,导致消息延迟或重复消费,消费者会有明显的感知;此外, 基于队列的模型非常容易导致一个用户饱受困扰的问题:单个故障消费者消费卡住会导致消息在服务端大量堆积。


RocketMQ5.0无状态代理模式

3.png


为了解决上述痛点,RocketMQ 5.0 提出了无状态代理模式。


新架构在原先的客户端和Broker中间插入了代理层。策略上是将客户端的无状态功能尽可能下移到代理层,同时也将 Broker侧的无状态功能尽可能上移到代理层。在这里,我们将客户端的原有的负载均衡机制、故障隔离、push/pop消费模型下移到了代理层,将 Broker 的访问控制、多协议适配、客户端治理以及NameServer 的消息路由能力上移到了代理层,最终打造出的代理层的丰富能力,包含访问控制、多协议适配、通用业务能力、治理能力以及可观测性等。


在构建代理层的过程中,我们必须坚持的一个原则就是:客户端和 Broker 往代理层迁移的能力必须是无状态的,这样才能保证后续代理层是可以随着承接的流量大小进行动态扩缩容的。


4.png

在引入无状态代理层后,RocketMQ原先客户端、Broker的直连架构就演变为上图的无状态代理模式架构:

从流量上看,代理层承接了客户端侧所有流量, Broker 和 NameServer 不再直接对用户暴露,用户唯一能看到的组件只有代理层(Proxy)。


这里,Proxy的职责包括以下几个方面:

  • 多协议适配: Proxy具备解析和适配不同协议的能力,包含 remoting 、gRPC、HTTP 以及后续可能衍生出来的MQTT和AMQP等协议。Proxy对不同协议进行适配、解析,最终统一翻译成与后端 Broker 和 NameServer 之间的 remoting协议。
  • 流量治理和流量分发: Proxy承接了客户端侧所有流量,因此能够很轻松地基于某些规则识别出当前流量的特性,然后根据一定的规则将流量分发到后端不同的 Broker集群,甚至进行精准的流量控制、限流等。
  • 功能扩展:包括访问控制比如允许哪个用户访问后端Broker集群中的哪个 Topic、消息轨迹的统一收集以及整体的可观测性等。
  • Proxy能扮演NameServer,交付给客户端查询TopicRoute的能力。
  • Proxy能够无缝兼容用户侧的Pop或者Push消费模式:在Proxy和Broker侧采用Pop消费模式来避免单个队列被锁导致消息在服务端堆积的历史遗留问题。


同时,我们也可以看到Proxy具有以下两大特性:

① 无状态,可根据用户以及客户端的流量进行水平扩缩容。

② 计算型,比较消耗CPU,因此在部署时需要尽可能给Proxy分配多些CPU。


做下总结,无状态代理模式解决了原先架构的多个痛点:

① 将客户端大量业务逻辑下移到代理层,打造出轻量客户端。同时,依托于 gRPC协议的标准化以及传输层代码自动生成的能力,能够快速适配多种语言的客户端。

② 客户端只会与Proxy层连接,针对多网络类型接入的诉求,可以将多网络类型绑定到Proxy层,由于Broker 和 NameServer不再直接对客户端暴露,转而只需对 Proxy暴露内网的连接即可,多网络类型接入的诉求可以只在Proxy这个组件就封闭掉;同时,Proxy的无状态的特性保证了多类型网络接入是与集群规模无关的。

③ 消费模式进行了无感知切换,无论客户端侧选择的是Pop还是Push消费模式,最终统一替换为Proxy与Broker侧的Pop消费模式,避免单个客户端消费卡住导致服务端消息堆积的历史问题。


RocketMQ无状态代理模式技术详解

5.png


新架构在客户端和 Broker 之间引入了代理层,客户端所有流量都需要多一跳网络、多经历一次序列化/反序列化的过程,这对端到端消息延迟敏感的用户是极其不友好的,因此我们设计了合并部署形态。


合并部署形态下,Proxy和 Broker 按照1:1的方式对等部署,且 Proxy和 Broker 实现进程内通信,满足低延迟、高吞吐的诉求。同时,Proxy仍然具备多协议适配的能力,客户端会与所有 Proxy建立连接进行消息收发保证能够消费到所有消息。


代码实现上,我们通过构造器来实现合并部署和分离部署的两种形态。用户可自行选择部署形态。如果用户选择合并部署的形态,则在构建 Proxy处理器之前,会先构造 BrokerController,并向 Proxy的处理器注册,本质上是为了告知Proxy处理器:后续的请求往我这个BrokeController 发;如果用户选择分离部署模式,则无须构建BrokerController,直接启动Proxy处理器即可。


6.png


对于这两种部署模式的比较,首先,合并部署和分离部署同时具备了多协议的适配能力,都能够解析用户侧和客户端侧的多协议请求;且具备模型抽象,能够解决富客户端带来的一系列痛点。


部署架构上,合并部署是一体化的架构,易于运维;分离部署是分层的架构,Proxy组件独立部署,Proxy和 broker按业务水位分别进行扩缩。


性能上,合并部署架构少一跳网络和一次序列化,有较低的延迟和较高的吞吐;分离部署多一跳网络和一次序列化,开销和延迟有所增加。延迟具体增加多少主要依赖于 Proxy和 Broker 之间的网络延迟。


资源调度上,合并部署状态下比较容易获得稳定的成本模型,因为组件单一;分离部署形态下Proxy是 CPU 密集型,Broker和NameServer 也逐渐退化成存储和 IO 密集型,需要分配比较多的内存和磁盘空间,因此需要进行细粒度的分配和资源规划,才能让分离部署形态资源的利用率达到最大化。


多网络类型接入成本上,合并部署成本较高,客户端需要与每一个 Proxy副本都尝试建立连接,然后进行消息收发。因此,多网络接入类型场景下,Proxy进行扩缩容时需要为每台Proxy绑定不同类型的网络;分离部署模式成本较低,仅需要在独立部署的 Proxy层尝试绑定多网络类型的接入点即可,同时是多台Proxy绑定到同一个类型的网络接入点即可。


针对业务上的选型建议:

如果对端到端的延迟比较敏感,或期望使用较少的人力去运维很大集群规模的RocketMQ部署,或只需要在单一的网络环境中使用RocketMQ的,比如只需内网访问,则建议采用合并部署的模式。


如果有多网络类型接入的诉求比如同时需要内网和公网的访问能力或想要对RocketMQ进行个性化定制,则建议采用分离部署的模式,可以将多网络类型的接入点封闭在 Proxy层,将个性化定制的改造点也封闭在Proxy层。


7.png

社区新推出的PopConsumer消费模式和原先的PushConsumer 消费模式存在较大区别。PushConsumer 是基于队列模型的消费模式,但存在一些遗留问题。比如单个 PushConsumer 消费卡住会导致服务端侧消息堆积。新推出的Pop消费模式是基于消息的消费模型,PopConsumer 会尝试和所有 broker 连接并消费消息,即便有一个PopConsumer消费卡住,其他正常的PopConsumer依然能从所有 broker里拉取到消息进行消费,不会出现消息堆积。


从Proxy代理层角度看,它能够无缝适配 PushConsumer 和 PopConsumer,最终将两种消费模式都映射到 Pop 消费模式,与后端 Broker 建立消费连接。具体来看,PushConsumer 里的pull请求会被转成PopConsumer 消费模式里的 pop 请求,提交位点的 UpdateConsumeOffset 请求会被转换成消息级别的 ACK 请求,SendMessageBack会被转换成修改消息的不可见时间的请求,以达到重新被消费的目的。


8.png

Proxy最上层为协议的适配层,通过不同的端口对客户端暴露服务,不同协议通过不同端口请求到Proxy之后,协议适配层会进行适配,通过通用的 MessagingProcessor 模块,将send、pop、ack、ChangeInvisibleTime等请求转换成后端 Remoting 协议的请求,与后端的 Broker 和NameServer建立连接,进行消息收发。


多协适配的优势有以下几个方面:

① 加速了RocketMQ的云原生化,比如更容易与Service Mesh相结合。

② 基于 gRPC 的标准性、兼容性及多协议多语言传输层代码的生成能力,打造RocketMQ的多语言瘦客户端,能够充分利用gRPC插件化的连接多路复用、序列化/反序列化的能力,让RocketMQ客户端更加轻量化,将更多精力聚焦在消息领域的业务逻辑。


9.png

做下技术方案的总结:

无状态代理模式通过客户端下移、Broker侧上移无状态的能力到代理层,将访问控制、客户端治理、流量治理等业务收敛到代理层,既能够满足快速迭代的诉求,又能对变更进行收敛,更好保障整个架构的稳定性:有了分层架构之后,更多业务逻辑的开发会聚焦在 Proxy层,下一层的 Broker和 NameServer 趋于稳定,可以更多地关注存储的特性。Proxy的发布频率远远高于底层 Broker 的发布频率,因此问题收敛之后,稳定性也得到了保证。


多协议适配,基于gRPC的标准性、兼容性以及多语言传输层代码生成的能力打造RocketMQ的多语言瘦客户端。


Push 到 Pop 消费模式的无感知切换,将消费位点的维护收敛到 Broker, 解决了单一消费者卡住导致消息堆积的历史遗留问题。


另外,我们也尝试探索了可分可合的部署形态,保证同一套代码可分可合,满足不同场景下对性能部署成本、易运维性的差异化诉求。在大部分的场景下,依然建议选择合并部署的形态。如果有对多网络类型接入的诉求,或对RocketMQ 有极强的定制化诉求,则建议选择分离部署的形态,以达到更好的可扩展性。


代理层无状态的特性,极大降低了适配多类型网络接入诉求的成本。


未来规划

10.png


未来,我们期望RocketMQ底层的Broker和NameServer 更多聚焦在存储的特性上,比如业务型消息存储的事务、定时、顺序等,快速构建消息索引、打造一致性多副本提升消息可靠性、多级存储来达到更大的存储空间等。


其次,对无状态代理层依照可插拔的特性开发,比如对访问控制、抽象模型、协议适配、通用业务能力、治理能力等按模块进行划分,使语义更丰富,可按照不同场景的诉求可插拔地部署各种组件。


最后,我们期望这一套架构能够支持阿里云上的多产品形态,致力于打造云原生消息非常丰富的产品矩阵。


加入 Apache RocketMQ 社区


十年铸剑,Apache RocketMQ 的成长离不开全球接近 500 位开发者的积极参与贡献,相信在下个版本你就是 Apache RocketMQ 的贡献者,在社区不仅可以结识社区大牛,提升技术水平,也可以提升个人影响力,促进自身成长。

社区 5.0 版本正在进行着如火如荼的开发,另外还有接近 30 个 SIG(兴趣小组)等你加入,
欢迎立志打造世界级分布式系统的同学加入社区,添加社区开发者微信:rocketmq666 即可进群,参与贡献,打造下一代消息、事件、流融合处理平台。

11.jpeg

微信扫码添加小火箭进群

另外还可以加入钉钉群与 RocketMQ 爱好者一起广泛讨论:

12.png

钉钉扫码加群

关注「Apache RocketMQ」公众号,获取更多技术干货

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
消息中间件 弹性计算 Java
Rocketmq-spring入门与实践
本场景带您体验如何在 Spring 生态中优雅地使用 Apache RocketMQ,感受最受欢迎业务开发框架与最受欢迎消息平台结合的魅力。
|
2月前
|
消息中间件 存储 Serverless
【实践】快速学会使用阿里云消息队列RabbitMQ版
云消息队列 RabbitMQ 版是一款基于高可用分布式存储架构实现的 AMQP 0-9-1协议的消息产品。云消息队列 RabbitMQ 版兼容开源 RabbitMQ 客户端,解决开源各种稳定性痛点(例如消息堆积、脑裂等问题),同时具备高并发、分布式、灵活扩缩容等云消息服务优势。
113 2
|
3月前
|
消息中间件 Java Apache
RocketMQ消息回溯实践与解析
在分布式系统和高并发应用的开发中,消息队列扮演着至关重要的角色,而RocketMQ作为阿里巴巴开源的一款高性能消息中间件,以其高吞吐量、高可用性和灵活的配置能力,在业界得到了广泛应用。本文将围绕RocketMQ的消息回溯功能进行实践与解析,分享工作学习中的技术干货。
91 4
|
4月前
|
消息中间件 弹性计算 Kubernetes
RabbitMQ与容器化技术的集成实践
【8月更文第28天】RabbitMQ 是一个开源消息代理和队列服务器,用于在分布式系统中存储、转发消息。随着微服务架构的普及,容器化技术(如 Docker 和 Kubernetes)成为了部署和管理应用程序的标准方式。本文将探讨如何使用 Docker 和 Kubernetes 在生产环境中部署和管理 RabbitMQ 服务,同时保证高可用性和弹性伸缩能力。
85 3
|
3天前
|
消息中间件 Java 开发工具
【实践】快速学会使用云消息队列RabbitMQ版
本次分享的主题是快速学会使用云消息队列RabbitMQ版的实践。内容包括:如何创建和配置RabbitMQ实例,如Vhost、Exchange、Queue等;如何通过阿里云控制台管理静态用户名密码和AccessKey;以及如何使用RabbitMQ开源客户端进行消息生产和消费测试。最后介绍了实验资源的回收步骤,确保资源合理利用。通过详细的操作指南,帮助用户快速上手并掌握RabbitMQ的使用方法。
34 10
|
2月前
|
消息中间件 安全 Java
云消息队列RabbitMQ实践解决方案评测
一文带你详细了解云消息队列RabbitMQ实践的解决方案优与劣
93 10
|
2月前
|
消息中间件
解决方案 | 云消息队列RabbitMQ实践获奖名单公布!
云消息队列RabbitMQ实践获奖名单公布!
|
2月前
|
消息中间件 存储 弹性计算
云消息队列RabbitMQ实践
云消息队列RabbitMQ实践
|
2月前
|
消息中间件 存储 弹性计算
云消息队列 RabbitMQ 版实践解决方案评测
随着企业业务的增长,对消息队列的需求日益提升。阿里云的云消息队列 RabbitMQ 版通过架构优化,解决了消息积压、内存泄漏等问题,并支持弹性伸缩和按量计费,大幅降低资源和运维成本。本文从使用者角度详细评测这一解决方案,涵盖实践原理、部署体验、实际优势及应用场景。
|
2月前
|
消息中间件 存储 监控
解决方案 | 云消息队列RabbitMQ实践
在实际业务中,网站因消息堆积和高流量脉冲导致系统故障。为解决这些问题,云消息队列 RabbitMQ 版提供高性能的消息处理和海量消息堆积能力,确保系统在流量高峰时仍能稳定运行。迁移前需进行技术能力和成本效益评估,包括功能、性能、限制值及费用等方面。迁移步骤包括元数据迁移、创建用户、网络打通和数据迁移。
72 4

相关产品

  • 云消息队列 MQ