RocketMQ 在小米的多场景灾备实践案例

news2025/1/11 2:52:29

作者:邓志文、王帆

01 为什么要容灾?

在小米内部,我们使用 RocketMQ 来为各种在线业务提供消息队列服务,比如商城订单、短信通知甚至用来收集 IoT 设备的上报数据,可以说 RocketMQ 的可用性就是这些在线服务的生命线。作为软件开发者,我们通常希望服务可以按照理想状态去运行:在没有Bug的前提下,系统可以提供正常的服务能力。

但现实的运维经验告诉我们这是不可能的,硬件故障是非常常见的问题,比如内存故障、磁盘故障等,甚至是机房相关的故障(专线故障、机房拉闸等)。因此我们需要对数据进行备份,使用多副本的方式来保证服务的高可用。Apache RocketMQ 设计上就支持多副本、多节点容灾,比如 Master-Slave 架构、DLedger 部署模式。

在小米内部,因为是面向在线业务,服务的恢复速度至关重要,而基于 Raft 协议的 DLedger 模式可以实现秒级 RTO,因此我们在 2020 年初选用了 DLedger 架构作为基本的部署模式(在 5.0 中,主从模式也可以做到自动 failover)。支持机房灾备需要增加额外的成本,下面我将用三个灾备部署的实践案例,讲解小米如何在成本和可用性的取舍上去支持灾备。

02 怎么去做容灾?

单机房高可用

实际在使用中,有许多业务是不需要机房级别容灾的,只要能够做到单机房高可用即可。Apache RocketMQ 本身就是分布式的消息队列服务,可以很好的做到同机房多节点高可用,下面主要分享下小米在权衡成本、可用性的前提下,如何去做部署架构的升级优化。

我们知道在 Raft 协议中,一般配置三个节点,利用机器冗余 + 自动选主切换来实现高可用的目标。因此在小米引入 RocketMQ 之初,单 Broker 组均部署三个 Broker 节点。同时为了保证集群中始终存在 Master 节点,我们一般会至少部署两个 Broker 组,一个简单的部署架构图如下:

在这里插入图片描述

可以说是一个很基本的部署架构,在单个机房中,通过多副本、多Broker组做到了单机房容灾。但不难发现,这样做有一个很严重的问题:资源浪费。RocketMQ 的从节点只有在客户端读取较旧的数据时才会起到从读的作用,其他时候都只是单纯地作为副本运行,机器利用率只有33%,这是让人无法忍受的。

出于成本上的考虑,我们需要重新思考现有的部署架构,如何才能利用起来从节点呢?一个很简单的思路便是节点混布:在从节点也部署 Broker 进程,让其可以作为 Master 来提供服务。比较巧合的是,社区当时也提出了 Broker Container 的概念,方案的原理是在 RocketMQ Broker 之上抽象一个 Container 角色,Container 用来管理 Broker 的增删改查,以此来达到单台服务主机上运行多个 Broker 的目的,具体架构图如下所示:

在这里插入图片描述

可以看到,Container 作为进程运行,原本的 Broker 被抽象为 Container 的一部分,同样的 3 台机器上我们可以运行 9个 Broker 节点,组成三个 Broker组,每台服务主机上存在一个 Master 节点,使用 Container 对等部署 Broker 之后,每台服务主机都得到了利用,同样的机器数,理论上可以提供三倍的性能。

Container 是一种很好的部署思想:主从节点对等部署进而充分利用所有的机器。 我们尝试直接使用该方案,但遇到了一些问题:

  1. Container 本质上是一个进程。不管其内运行了多少个 Broker ,我们只要对其进行重启操作,都会影响该 Container 内部 Broker 相关的所有 Broker 组,升级时会产生较为严重的影响;

  2. Container 自己维护 Broker 的上下线,无法与小米内部部署工具结合使用。

因此 Container 并不适合小米内部,但受 Broker Container的启发,我们提出了另一种与之类似的部署方案——单机多实例。所谓单机多实例,即单台主机上部署多个 Broker 实例,服务主机就是我们的 Container,Broker 以进程的方式运行,这样各个 Broker 之前不会相互影响,同时也可以和内部部署工具完美结合。一个简单的部署架构如下所示:

在这里插入图片描述

至此,小米内部完成了 RocketMQ 部署架构的第一次升级,集群中的节点数直接减少了 2/3。在成本优化的前提上依然提供 99.95% 的可用性保障。

多机房容灾 -Ⅰ

随着业务的不断接入,一些业务提出了机房灾备的需求。机房故障的概率虽然极低,但是一旦出现,其带来的影响是非常大的。比如机房故障导致 RocketMQ 不可用,那么作为流量入口,将会影响到所有的依赖业务。

在多机房容灾上,我们结合内部其他服务的部署经验,先提出了多集群多活的方式,即每个可用区部署一个集群,提供多个集群供业务容灾,方案部署架构如下:

在这里插入图片描述

用户视角看到的是三个独立的集群,需要在相同的可用区部署客户端去读写同机房的 RocketMQ 集群。举个例子:可用区1的客户端正常情况下访问可用区1的 RocketMQ 集群Cluster-1,当Cluster-1故障时,用户需要手动更改客户端的连接地址来切换集群,进而将流量转移到其他机房的集群中。用户可以通过配置下发去热更新连接地址,也可以修改配置重启客户端来切换,但这一切的操作前提都是:需要业务感知到 RocketMQ 集群故障,手动触发才可以。

▷优点

  • 不用跨区同步数据,低延时(P99写入10ms)高吞吐(单Broker组写入TPS达100K)

  • 部署架构简单,稳定性高

▷缺点

  • 集群需预留灾备buffer,确保故障时,存活集群可承载故障集群的全部流量

  • 需要业务自己手动切换集群,不够灵活

  • 若消费存在堆积,故障集群的消息将可能不会被消费,恢复后可消费

▷生产耗时

在这里插入图片描述

多机房容灾 -Ⅱ

可以看到,业务如果选择以上方式接入的话,需要做一定的适配工作,该方案适用于流量较大的业务接入。然而有一些业务希望可以低成本接入:不做适配,直接使用SDK接入,我们结合 DLedger 自动切换的特性,实验性的部署了机房故障服务自动 failover 的 模式,部署架构如下所示:

在这里插入图片描述

用户视角看到的就是一个独立的 RocketMQ 集群,使用 SDK 正常接入即可,无需任何适配。机房故障时依赖 DLedger 自动切主做流量切换。

▷优点

  • 部署方便,充分利用 RocketMQ 的原生能力

  • 自动选主,业务接入方便,无需业务手动切换流量

▷缺点

  • 跨机房部署,容易受网络波动,集群抖动概率较大

  • 跨机房部署,会增加写入延时,从而降低集群吞吐能力

▷生产耗时

在这里插入图片描述

多机房容灾 - PLUS

目前看来 RocketMQ 服务已经在小米完成了很好的落地,日消息量也达到了千亿规模,但我们仔细观察以上两个方案不难发现,虽然可以实现机房故障切换,但都有一定的缺点,简要概况如下:

  • 多机房容灾 -Ⅰ:同机房请求,延时较低,但需业务手动切换集群

  • 多机房容灾 -Ⅱ:自动切流、可消费历史数据,但对专线负载高,需三个Region才可部署

方案总是存在不够完美的地方,但不论作为服务的开发者还是业务使用者,其实都希望可以在实现以下几个目标的前提下做到灾备:

1)低成本:双Region可以完成部署;

2)低耗时:尽量同机房请求,减少网络耗时;

3)自动切流:机房故障时,可自动将流量切到正常的机房内。

为了实现以上的需求,我们从 RocketMQ 自身的架构出发,希望能够以最低的改造成本支持灾备。我们发现客户端都是根据 Namesrv 返回的元数据进行生产、消费,只要客户端能够在机房故障时,可以根据元数据自动将流量切走即可,因此我们将视角移到了客户端,希望从客户端上支持灾备的功能。

RocketMQ 所有 Broker 都会将自己注册到 Namesrv 上去,一旦某个 Broker 组故障,那么它的信息将会被从 Namesrv 中移除,客户端也就无法再向这类 Broker 组发送、拉取消息。基于以上逻辑,只要我们将 Broker组部署在不同机房中,便可以做到机房级别的灾备效果。部署架构如下:

在这里插入图片描述

我们以一个实际的例子来讲解以上方案的可行性:Topic-A 在两个可用区上均存在分区,SDK在使用时需要配置自己所在的region。

对于生产者来说,客户端只会向位于相同可用区的分区发送消息。例如:位于可用区1的客户端只会向可用区1发送消息,当可用区1故障时,由于在可用区1不存在可写的分区,便会开始向可用区2发送消息,从而实现生产侧的自动切流。消费者同样需要配置 region ,所有的消费实例会先按照可用区分别去做 rebalance:分区会优先被相同可用区的消费者去分配消费。当可用区1故障时,由于生产者已经将流量切走,因此消费者不需要做特殊变更就做到了消费自动切流。

在这里插入图片描述

该方案对于业务来说是一个可选项,业务可自行决定是否需要开启灾备模式,因此较为灵活,可以说是结合了以往两种机房灾备方案的优点,但是仍有不足之处,比如故障集群在故障期间历史消息不可被消费等,后续也会不断的优化方案。

03 来做个总结吧!

本文介绍了四种部署模式,针对不同的业务需求提供不同的部署模式,总结如下:

10.png

目前以上方案在小米内部均有具体的业务场景,消息量约占总体的 90%,未来也会逐步将剩余流量相关集群全部升级为机房灾备集群,从而提供 99.99% 的可用性服务能力。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/559535.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

我写了个操作系统,却被别人给骂了!

前言 哈喽,小伙伴们好,我是子牙。是一个擅长深入研究Windows内核、Linux内核、Hotspot源码的资深程序员,之前是JVM专家,手写过JVM。所以做老师后,第一个打造的课程便是《手写JVM》小班, 一经推出就受到了学…

我的苹果手机的越狱之旅

最近因为业务需要,需要一台越狱手机;就把测试机6plus拿来做越狱使用,在此之前先大致说明一下越狱的原理、应用、流程以及可能存在的问题: 越狱是指通过一些技术手段,使iOS设备可以访问到iOS系统的全部控制权&#xff0…

抛弃Vuex,使用Pinia

Pinia 符合直觉的 Vue.js 状态管理库 文章目录 Pinia 符合直觉的 Vue.js 状态管理库1.简介2.为什么要使用Pinia3.安装3.1 挂载pinia 4.创建一个store容器4.1 Option 参数4.2 Setup 参数 5.三个重要概念5.1 State5.2 Getter**5.3 Action** 6.购物车实例6.1 商品列表组件 1.简介 …

【Python-Django】如何在一个项目中创建多个app模块

django开发案例:a​​​​​【Django】开发日报_1_Day:用户管理系统案例-创建项目_django 开发用户管理系统_代码骑士的博客-CSDN博客 前面做过的管理系统项目功能比较单一,只用一个模块就能解决问题。如果想创建多个不同的模块的话&#xf…

Nodejs之HTTP模块

目录 前言一,创建HTTP模块1.1 基本使用1.2 注意事项 二,查看报文2.1 浏览器查看HTTP报文2.2 利用request获取HTTP请求报文2.2.1 获取请求行和请求头 2.2.2 获取请求路径2.2.3 获取查询字符串 三,跟请求报文相关的练习四,设置响应报…

聊天机器人开发实战--(微信小程序+SpringCloud+Pytorch+Flask)【完整版】

文章目录 前言架构小程序端管理端运维端 交互聊天页面聊天发送流程历史聊天记录个人中心 总结 前言 没想到从五一之后,到现在鸽了那么久。没办法,实话实说,确实忙,五一期间就没怎么休息,开局第一周,准备IE…

Scala学习(七)---面向对象特质

文章目录 1.面向对象特质(Trait)2.特质声明2.1 特质的特点2.2 特质冲突2.3 特质叠加2.4 特质自身类型2.5 特质和抽象类的区别扩展 1.面向对象特质(Trait) 在Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质…

分享7款优质免费的Figma“中文插件”

今天我要向你们分享一些 Figma 的“中文插件”,这些插件不仅功能强大,而且免费使用,非常方便,而且是完全中文的页面使用起来非常便捷,可以大大提高设计师的效率和体验。 1、「平面 3D」 插件 首先是平面 3D 插件。该…

OpenVINO 2022.3之九:Post-training Optimization Tool (POT)

OpenVINO 2022.3之九:Post-training Optimization Tool (POT) Post-training Optimization Tool (POT) 通过在已训练好的模型上应用量化算法,将模型的权重和激活函数从 FP32/FP16 的值域映射到 INT8 的值域中,从而实现模型压缩,以…

驱动开发:内核实现进程汇编与反汇编

在笔者上一篇文章《驱动开发:内核MDL读写进程内存》简单介绍了如何通过MDL映射的方式实现进程读写操作,本章将通过如上案例实现远程进程反汇编功能,此类功能也是ARK工具中最常见的功能之一,通常此类功能的实现分为两部分&#xff…

WXSS 模板样式

WXSS WXSS(WeiXin Style Sheets)是一套样式语言,用来美化 WXML 的组件样式,类似于网页开发中的 CSS WXSS 和 CSS 的关系 WXSS 具有 CSS 大部分特性,同时,WXSS 还对 CSS 进行了扩充以及修改,以…

AJ-Report是一个完全开源,拖拽编辑的可视化设计工具

简介 AJ-Report是全开源的一个BI平台,酷炫大屏展示,能随时随地掌控业务动态,让每个决策都有数据支撑。     多数据源支持,内置mysql、elasticsearch、kudu驱动,支持自定义数据集省去数据接口开发,目前已支…

分布式应用之监控平台zabbix

1.监控系统的相关知识 1.1 监控系统运用的原因 当我们需要实时关注与其相关的各项指标是否正常,往往存在着很多的服务器、网络设备等硬件资源,如果我们想要能够更加方便的、集中的监控他们,zabix可以实现集中监控管理的应用程序 监控的初衷…

历届蓝桥杯青少年编程比赛 计算思维题真题解析【已更新3套 持续更新中】

一、计算思维组考试范围 计算思维组面向小学生(7-12 岁,约 1-6 年级),通过设计多个角度的考核题目、层次科学的试卷组合、线上限时的考试形式,更加精确地考查学生的计算能力、反应能力、思维与分析能力,使…

【产品成长】产品专业化提升路径

产品专业化 产品专业化就是上山寻路。梳理一套作为产品经理的工作方法。 以图为例,做一个归纳。 第一:梳理自己的设计方法。就是拿到一个需求点之后,如何进行需求分析,如何还原业务情况,最终进行产品设计&#xff0c…

基于QEMU的RISC-V架构linux系统开发(三)——基于buildroot的最小根文件系统配置与编译

1.buildroot官网下载最新版本的buildroot。 https://buildroot.org/download.html 图1 下载最新版本的buildroot压缩包 2.拷贝buildroot软件包到工作目录,并解压buildroot。 图2 解压buildroot软件包 3.新建编译脚本build_risc-v.sh,使用buildroot自带的…

深度学习笔记之递归网络(五)递归神经网络的反向传播过程

机器学习笔记之递归网络——递归神经网络的反向传播过程 引言回顾:递归神经网络的前馈计算过程场景构建前馈计算描述 反向传播过程各参数的梯度计算各时刻损失函数梯度计算损失函数对各时刻神经元输出的梯度计算 Softmax \text{Softmax} Softmax回归的梯度计算关于 …

JAVA将xml数据转为实体类

使用 JAXB(Java Architecture for XML Binding) 实现XML与Bean的相互转换 介绍 JAXB是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB也提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象…

2023年7大人工智能技术趋势你有了解过嘛

人工智能 (AI) 已经接管世界,并且将在2023年继续向前发展。在2023年,它将完全实现自动化供应链、虚拟助手等多个产品与形态。 如今,世界正在经历一波人工智能驱动的全球经济转型浪潮。 当前之态势,人工智能 (AI) 技术几乎在每个领…