作者:邓志文、王帆
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 是一种很好的部署思维:主从节点对等部署进而充分利用所有的机器。 咱们尝试间接应用该计划,但遇到了一些问题:
- Container 实质上是一个过程。不论其内运行了多少个 Broker,咱们只有对其进行重启操作,都会影响该 Container 外部 Broker 相干的所有 Broker 组,降级时会产生较为重大的影响;
- 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 来做个总结吧!
本文介绍了四种部署模式,针对不同的业务需要提供不同的部署模式,总结如下:
目前以上计划在小米外部均有具体的业务场景,音讯量约占总体的 90%,将来也会逐渐将残余流量相干集群全副降级为机房灾备集群,从而提供 99.99% 的可用性服务能力。