基于云基础设施快速部署 RocketMQ 5.0 集群

简介: 如何解决在云基础设施上部署 RocketMQ 时面临多节点部署带来的高操作成本等诸多挑战?快来了解 RocketMQ Operator 是怎样支撑 RocketMQ 集群在云基础设施上的自动化运维与管理吧!

本文作者:蔡高扬,Apache RocketMQ Committer, 阿里云智能技术专家。

背景

上图左侧为 RocketMQ 4.x版本集群,属于非切换架构。NameServer 作为无状态节点可以部署多份,broker 集群可以部署多组 broker ,每一组有一个 Broker Master 和多个 Broker Slave 。运行过程中如果某一组 master 故障,消息发送会路由到正常的 master 上,普通消息可以从原 Broker Slave 继续消费。

但非切换架构存在若干问题,比如定时消息或事务消息需要由 Master 进行二次投递,如果 Master 故障,则需要人工介入将 Master 重新恢复。因此, RocketMQ 5.0 提出了自主切换架构。

自主切换架构新增了一个 Controller 模块,负责选主。当某个 Broker Master 故障,会选择合适的 Broker Slave 提升为 Master,无需人工介入。


如果要在生产环境中部署一套集群,需要规划整个集群的机器资源(比如哪些模块部署在哪些机器、哪些机器需要什么样的资源规格等),然后安装 JDK 等依赖软件。每个组件还需要准备有其配置文件、启动脚本,再启动各个组件。整个过程十分耗费人力,而且存在误操作可能。

而在云基础设施上部署 RocketMQ 面临更多挑战:

首先,在云基础设施上创建不同规格的虚拟机更为方便,因此在云基础设施上部署时,一个虚拟机上往往只会部署一个模块,以实现资源隔离。然而,多节点部署也带了更高的操作成本。而系统内部组件的宕机、恢复、迁移等行为也需要进行支持。

从社区角度看,因为社区面向不同用户,不同用户往往会在不同云基础服务提供商上进行部署。但是从 IaaS 层设施看,不同云厂商提供的接口并不统一。

为了解决上述问题,社区借鉴了面向接口编程的思路:不直接操作基础设施,而是通过标准接口。而 Kubernetes 正是这样一个容器编排的“标准接口”。于是,社区在解决 RocketMQ 在云基础设施的部署问题时,选择基于 Kubernetes 进行部署,不同云厂商负责从 Kubernetes 到具体云 IaaS 层的调度:将有状态 RocketMQ 集群托管到 Kubernetes 集群,充分利用 Kubernetes 提供的部署、升级、自愈相关能力,同时也能享受到 Kubernetes 社区的生态红利。

Kubernetes 将 Pod、Deployment、Service、Ingress 等都封装成抽象资源。在部署 RocketMQ 集群时,只需将相关的 Kubernetes 资源编排好,而资源最终如何在云基础设施上进行编排则交由云服务提供商来完成。

然而,直接基于 Kubernetes 原生资源进行部署也存在一些不足。

比如用 Kubernetes 部署时,经常需要操作 YAML 文件,会涉及到 Deployment、StatefulSet、Service、Ingress 之类的资源需要大量配置,碰到复杂的资源定义就像“面向 YAML 编程”。

另外, Kubernetes 在支持有状态应用的管理上也存在局限。RocketMQ 集群的状态可归纳为两块。其一为集群拓扑关系,包括 RocketMQ Broker 主备关系以及 RocketMQ 不同模块之间的相互依赖(比如 Broker 需要依赖 NameServer、Controller 等);其二为存储状态,包括 Cluster 名称、 Broker 名称、 Broker ID 、新扩容 Broker 元数据等。

如何自动化管理以上状态也是必须解决的问题。

于是社区成立了 RocketMQ Operator 项目,用于支撑 RocketMQ 集群在云基础设施上的自动化运维与管理。

如上图所示,最右侧为 RocketMQ Operator 模块,实时与 Kubernetes API Server 进行交互。一方面会将 RocketMQ 集群(包括 NameServer、Broker 等模块)正常部署,同时也会利用 RocketMQ Admin Tool 实时地维护集群状态,比如 NameServer 地址等。

一、Kubernetes Operator原理

[]()

Kubernetes Operator 是一种相对简单灵活且编程友好的管理应用状态的解决方案。其工作原理分为两部分:一部分是利用自定义 API 资源( CRD )描述管理状态应用,可以认为是一个面向用户的接口,用户描述需要部署或运维的资源;另一部分是自定义控制器,根据自定义资源对象的变化完成运维动作。

上图中间的 Operator 控制循环可以视作自定义资源和 Kubernetes 资源之间的桥梁,它会不断监听自定义资源的状态变化,根据状态以及内部逻辑更新 Kubernetes 资源。同时也会根据 Kubernetes 资源的变化更新自定义资源的状态。

自定义对象与 Pod 或 Deployment 类似,只是它并不是 Kubernetes 内部提供的对象,而是需要用户自定义,并告知 Kubernetes。Custom Resource 指自定义API 资源的实例,Custom Resource Definition 指 CR 的定义。

如上图,比如有一个类型为 Container 的 CRD,定义了三个属性,分别是 Container 名称、Container 对应的 image 和 Container 监听的端口。下面的 CR 为具体自定义资源,其名称为 nginx,image 为 DockerHub 上的最新版本,监听80端口。与大家比较熟悉的数据库表进行类比,Container 可以认为是一张表,具体定义(Spec)可以类比为每一列的定义,每一行数据即不同的自定义资源(CR)。

自定义资源提供 API 对象,真正负责将自定义资源转换成 Kubernetes 内部资源的工作则由自定义控制器实现。

自定义控制器里有 Informer 模块,会不断地调用 Kubernetes API Server 的 listAndWatch 接口,以获得所监听 CR 的变化。CR 的变化事件和 CR 对象会被加入 Delta FIFO Queue,以 Key-Value 的方式保存在本地存储,并将 Key 加入 WorkQueue。最右侧的控制循环会不断地从 WorkQueue 取出相关 Key,根据 Key 从 Informer 的 Local Store 查询对应的 CR 对象。接下来将对象定义的期望状态与目前实际状态进行比对,如果有差异,则执行内部逻辑。最终使得实际状态与 CR 定义的期望状态达到一致。

二、RocketMQ Operator设计

社区在实现 RocketMQ Operator 时,并非直接通过 controller-runtime 底层接口,而是依赖 Operator SDK 作为脚手架,帮助生成相关代码。开发人员在进行 RocketMQ Operator 开发时,只需要专注 RocketMQ 集群本身的编排逻辑。


目前 RocketMQ Operator 的模块有 Name Service、Controller、Broker、TopicTransfer 和 Console,与 RocketMQ 模块基本一致。各模块通过不同 CRD 进行编排,其优点为架构、代码比较清晰,不同对象均有独立的 CRD 定义和对应的 Controller 实现。缺点为缺少 RocketMQ 集群维度的描述,代码实现、配置上可能存在重复。关于 CRD 的演进,欢迎社区同学结合各自的实践提出建议。

Name Service 模块负责 NameServer 在 Kubernetes 集群的运维管控操作,包括部署、扩缩容、提供 NameServer 集群IP列表等。Broker 需要向 NameServer 注册路由信息,因此 NameServer 的地址极为重要,需要作为内部状态实时地进行维护。当 NameServer 进行扩缩容时,Broker 集群能够自动感知 NameServer 地址的更新。

上图为 NameServer CR 定义示例,主要属性有:

  • NameServer 集群实例数
  • NameServer 镜像
  • hostNetwork 可以设置为 true 或 false ,true 则表示通过 hostNetwork 提供 Node IP,供 Kubernetes 集群外部的客户端访问。

Controller 模块定义了 Dledger controller 集群。当 Broker 启用自主切换模式时,需要维护 Controller 的访问地址,其中采用了两种机制:

第一种:Service。该方式会暴露 Controller 集群的统一访问地址供Broker 访问。Broker 的访问请求会路由到任意 Controller 节点,Controller 节点会返回 Controller 主节点的访问地址,Broker 再与 Controller 主节点进行通讯。

第二种:Headless Service。该机制为每一个 Controller 的提供访问地址,用于 Controller 间进行服务发现。在组建 Controller 集群时,Controller 节点必须与具体的某个 Controller 节点进行通信,因此必须为一对一关系。

Controller 的定义相对简单,只需提供 Controller 数量(数量必须为奇数)、 Controller image ,其他与 NameServer 类似,比如资源、存储的定义。

Broker 模块用于定义 Broker 集群,维护 Broker 组数量以及每组的节点数量,同时负责处理 Broker 集群的运维操作,包括部署、扩缩容以及元数据复制。扩容时,如果新扩容的 Broker 没有 Topic 等元数据,用户流量实际上不会路由到此 Broker。因此,Broker 模块还会负责 Broker 扩容后进行元数据复制。

Broker 的定义相对复杂,包括:

  • Broker组的数量。
  • 每组的节点数。
  • clusterMode定义了broker集群模式,默认部署非切换集群,设置为Controller则部署自主切换集群。
  • 其余还包括资源、存储定义等。

TopicTransfer 不是与 RocketMQ 直接映射的模块,它定义了 Topic 和 Consumer Group 元数据迁移运维操作。使用 TopicTransfer 迁移元数据时,首先在目标集群创建指定的 Consumer group 和 Topic ;创建完成后禁写原集群,使得消息不会发送到原集群;等待原集群的消息消费完成后,会将原集群的元数据进行清理。在此过程中,任何一步失败均会进行回滚,确保元数据正确迁移。

Console 模块负责部署 RocketMQ 控制台以及维护其用到的 NameServer 地址,功能相对简单,目前 RocketMQ Console 为无状态节点,其定义方式与 Deployment 的相同。

接下来介绍几个重要的控制器实现。

NameServer 控制器首先会判断 Name Service 对应的 StatefulSet 是否存在,如果不存在,则创建或更新 StatefulSet,直至 NameServer 节点数与期望值相同。然后列出 NameServer 对应的 Pod 地址,并判断地址是否发生了变化。如果是,则会将集群中的 NameServer 地址进行更新,从而保证 Broker 或其他模块能够获取到正确的 NameServer 地址。

Dledger Controller 先创建 Headless Service 用作组建 Controller 集群时服务发现的入口,接着判断 Controller 节点数量是否与期望值一致,如果不一致,则创建 StatefulSet。创建 StatefulSet 时会自动为每个 Dledger Controller 分配 controllerDledgerSelfId。期望节点数目与实际节点数目一致后,才会暴露 Controller 的 Service 地址,供 Broker 访问。

Broker 是有状态应用,因此在扩容或缩容时需要 Broker Controller 进行额外动作。Broker Controller 会以 Broker 组为单位进行调度,每一个 broker 组有 1个 master 节点,并配置 0 到多个 slave 节点。当 Broker 进行扩容时,会新增一组 Broker 并按照用户配置复制元数据到新扩容的 Broker。

Broker 依赖 NameServer和 DLedger Controller,因此会等待 NameServer 、 DLedger Controller 启动完成且两者均正常提供服务后,才会进一步创建 Broker 对应的 StatefulSet ,直到实际节点数目与期望节点数一致。

如果出现扩容情况,则会根据在 CR 定义 的 ScalePodName 字段对应 Pod 将元数据(包括 Topic 、消费组)拷贝到新扩容的 Broker 。

三、快速部署RocketMQ集群

首先,将 RocketMQ Operator 项目克隆到本地,解压后执行 install-operator.sh 脚本即可完成 RocketMQ Operator 的安装。

第二步,配置 Name Service CR。Name Service CR 配置较为重要的字段有两个,其一为 size,即需要部署了多少个 NameServer 节点,其二为 hostNetwork ,默认 false ,此时客户端只能在 Kubernetes 集群内与 NameServer 进行通讯。如果Kubernetes 集群外的客户端需要访问到 RocketMQ 集群,需要将 hostNetwork 配为 true ,NameServer 的接入点需要配置为 NameServer 所在的 Node IP。

第三步,配置 Controller CR。注意 size 需要配置为奇数。Controller 的数据需要持久化存储,可以利用云服务提供商提供的 StorageClass,无需自行维护存储。如果希望配置自己的存储,GitHub 上 RocketMQ Operator 项目代码提供了配置 NFS 存储的相关示例。

第四步,配置 Broker CR。示例中配置了两组 Broker,每组有一个备节点,同时将 clusterMode 设置为 Controller,启动自主切换架构集群。

准备好以上三个模块的相关配置文件之后,执行 kubectl apply 命令提交给 Kubernetes 集群。其余的部署、运维等动作均交由 RocketMQ Operator 自动完成。

成功部署后,可以通过 kubectl get po 命令查看部署的Pod。可以看到部署了4个Broker节点、Controller 和 NameSever 节点各3个。

进入一个 Broker Pod,可以使用 clusterlist 命令查看集群状态,可以看到集群有两组 Broker,每一组各有一主(BID=0)一备。

四、未来展望

RocketMQ Operator 将不断完善,全面支持 RocketMQ 5.0,后续规划主要包含以下工作:

① 镜像统一。目前 RocketMQ Operator 内部也维护了一套 RocketMQ 镜像,但是已经有 RocketMQ Docker 项目,没必要再维护一套镜像。因此,未来社区希望将对两边镜像进行统一,降低管理成本。

② 集群管理。RocketMQ 5.0 版本还提供了另外一种集群部署方式—— BrokerContainer 对等部署。与 4.0 版本传统的主备方式不同, BrokerContainer 会在进程中同时启动一主一备,有两个 BrokerContainer 中的 Broker 互为主备。某一个Container 的主节点故障时,则配对的 Container 中的备节点会进入 Slave Acting Master 状态,负责代理主节点进行定时消息或事务消息等二级消息的处理。

③ 支持部署更多 RocketMQ 组件,包括 RocketMQ Schema Registry、RocketMQ Proxy、RocketMQ Exporter 等。

相关实践学习
消息队列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
相关文章
|
7天前
|
消息中间件 存储 运维
2024最全RabbitMQ集群方案汇总
本文梳理了RabbitMQ集群的几种方案,主要包括普通集群、镜像集群(高可用)、Quorum队列(仲裁队列)、Streams集群模式(高可用+负载均衡)和插件方式。重点介绍了每种方案的特点、优缺点及适用场景。搭建步骤包括安装Erlang和RabbitMQ、配置集群节点、修改hosts文件、配置Erlang Cookie、启动独立节点并创建集群,以及配置镜像队列以提高可用性和容错性。推荐使用Quorum队列与Streams模式,其中Quorum队列适合高可用集群,Streams模式则同时支持高可用和负载均衡。此外,还有Shovel和Federation插件可用于特定场景下的集群搭建。
89 2
|
26天前
|
消息中间件 监控 Java
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
32 6
|
7天前
|
消息中间件 RocketMQ
2024最全RocketMQ集群方案汇总
在研究RocketMQ集群方案时,发现网上存在诸多不一致之处,如组件包含NameServer、Broker、Proxy等。通过查阅官方文档,了解到v4.x和v5.x版本的差异。v4.x部署模式包括单主、多主、多主多从(异步复制、同步双写),而v5.x新增Local与Cluster模式,主要区别在于Broker和Proxy是否同进程部署。Local模式适合平滑升级,Cluster模式适合高可用需求。不同模式下,集群部署方案大致相同,涵盖单主、多主、多主多从等模式,以满足不同的高可用性和性能需求。
46 0
|
5月前
|
消息中间件 编解码 Docker
Docker部署RabbitMQ消息中间件
【7月更文挑战第4天】Docker部署RabbitMQ消息中间件
285 3
|
2月前
|
消息中间件 编解码 Docker
【Docker项目实战】Docker部署RabbitMQ消息中间件
【10月更文挑战第8天】Docker部署RabbitMQ消息中间件
128 1
【Docker项目实战】Docker部署RabbitMQ消息中间件
|
3月前
|
NoSQL 关系型数据库 Redis
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
mall在linux环境下的部署(基于Docker容器),docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongodb、minio详细教程,拉取镜像、运行容器
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
|
2月前
|
消息中间件
实践部署《云消息队列RabbitMQ实践》测评
《云消息队列RabbitMQ实践》解决方案原理清晰,尤其在异步通信和解耦方面解释详尽。对初学者而言,部分术语如消息持久化、确认机制及集群性能优化可更细致。部署过程文档详实,涵盖主要环节,但插件配置等细节存在环境问题,需查阅社区资料解决。该方案展示了RabbitMQ的高吞吐量、灵活路由和可靠消息传递能力,但在高可用性和消息丢失处理上可提供更深入配置建议。适用于高并发和解耦场景,如订单处理、日志收集,有助于提升系统可扩展性。总体部署体验良好,实用性较强。
58 0
|
4月前
|
消息中间件 存储 负载均衡
|
4月前
|
消息中间件 存储 负载均衡
"RabbitMQ集群大揭秘!让你的消息传递系统秒变超级英雄,轻松应对亿级并发挑战!"
【8月更文挑战第24天】RabbitMQ是一款基于AMQP的开源消息中间件,以其高可靠性、扩展性和易用性闻名。面对高并发和大数据挑战时,可通过构建集群提升性能。本文深入探讨RabbitMQ集群配置、工作原理,并提供示例代码。集群由多个通过网络连接的节点组成,共享消息队列,确保高可用性和负载均衡。搭建集群需准备多台服务器,安装Erlang和RabbitMQ,并确保节点间通信顺畅。核心步骤包括配置.erlang.cookie文件、使用rabbitmqctl命令加入集群。消息发布至任一节点时,通过集群机制同步至其他节点;消费者可从任一节点获取消息。
57 2
|
4月前
|
存储 C# 关系型数据库
“云端融合:WPF应用无缝对接Azure与AWS——从Blob存储到RDS数据库,全面解析跨平台云服务集成的最佳实践”
【8月更文挑战第31天】本文探讨了如何将Windows Presentation Foundation(WPF)应用与Microsoft Azure和Amazon Web Services(AWS)两大主流云平台无缝集成。通过具体示例代码展示了如何利用Azure Blob Storage存储非结构化数据、Azure Cosmos DB进行分布式数据库操作;同时介绍了如何借助Amazon S3实现大规模数据存储及通过Amazon RDS简化数据库管理。这不仅提升了WPF应用的可扩展性和可用性,还降低了基础设施成本。
98 0