互联网常见的高可用手段。比如服务冗余部署、异步化设计、负载均衡、服务限流降级熔断、架构拆分、服务治理、分布式存储等等,今天主要是一起聊下,多机房部署的灾备架构模式,来确保服务的高可用。
::: hljs-center
:::
灾备架构比较常见的几种模式,基本分为同城多中心、跨城多中心、跨国多中心。从字面上看,这几个架构模式好像差不多的,只是距离上的差异,其他的感觉都差不多的。但,就是简单的距离上的差异,就会导致在架构上关键的应用场景以及技术本质上有较大的区别。
::: hljs-center
:::
同城多中心最典型的就是双中心跟三中心。
简单来说就是在同一个城市部署两个机房。如下图中,IDC-1 和 IDC-2。两个机房之间通过高速光纤进行连接。它的一些关键特征是:
(1)相同城市,距离在 50km 以上。为什么需要在 50km 以上呢?如果从机房的建设上讲,没有什么不可以,相距 5km 也可以建设。但我们做双机房,是为了高可用灾备或者备份。一个简单的例子,如果距离过近,很可能是属于一个片区。如果遇到停电,很可能是一个片区的停电。这样两个机房都不可用了。(2)光纤互联(3)机房网络延迟<2ms
同城双中心的架构本质是同城双中心可以当做一个逻辑机房。也就是将同一个集群上的节点,部署在两个物理机房。这样可以应对机房级别的灾难。如下图所示
要注意,同一个集群,部署在两个数据中心,一般要用多条光纤线路,不然容易出现脑裂。此外还有些特别情况,如下图,可以发现,如果 IDC-2 挂了,IDC-1 能正常服务。但如果 IDC-1 整个挂了,DIC-2 的 Redis 集群是不可用的。这是因为 sentinel 节点不能完成选举,这里要从架构上进行考虑设计。当然也有个办法,就是在 idc-3 部署一个节点,只部署 sentinel 集群,来避免这个问题。在 IDC-3 不需要搭建完整机房,只需要部署部分决策选举相关的服务,有一定成本,但整体成本还是比较低的。
相比同城双中心,三中心就是在同一个城市部署三个机房,相互之间通过高速光纤连接。三中心,每个中心的定位跟职责都是一样的,比如业务要部署的话,三个都会部署。事实上,很少有公司采用这种架构。主要的原因是这种同城三中心的成本是比较高的,但是高可用并没有提高多少,如果发生城市级别的灾难,比如地震、台风等,这三个机房都会受到影响。所以说,想做三机房,一般都是一个同城双中心,然后另外一个机房部署到其他城市。
下图只是示意图,实际的架构要复杂得多。
::: hljs-center
:::
跨城多中心也分为跨城双中心和跨城三中心或者四中心等。看下图跨城双中心的架构跟同城双中心的架构是类似的,区别就是机房所在城市不一样。跨城双中心的一些关键特征是:不同城市、光纤互联。
跨城双中心主要的应用场景是 :
并不是所有的跨城多中心架构都能满足 这几个应用场景,不同的跨城双中心架构有不同的应用的场景。从城市的距离上,分为近邻城市和远端城市场景。
这个架构的关键点就是选择两个相近的城市,比如上海杭州、北京天津、广东深圳这种。机房的延时要<10ms,可以当做同一逻辑机房使用。
应用场景:
远端城市架构模式的关键特征是选择两个远距离的城市;机房延时>30ms,不能当作同一逻辑机房;
应用场景
跨城多中心的一般应用场景,就是用户分区、就近接入、异地多活。
可以结合 OceanBase 官方推荐架构来理解。如下图,采用两近(延迟 10ms)一远(延迟 30~50ms)的部署模式,可以应对城市级别故障,可靠性是最高的;不过成本也是最高的。为什么要 2 近 1 远?其实这跟 oceanBase 本身的技术实现有关系,底层为了保证一致性,是通过 proxy 协议不断的进行通信、投票来保障的,必须要保证服务之间通信的性能。一远是为了保证应对城市级别的故障。
::: hljs-center
:::
跨国数据中心的基本特点:(1)全球部署(2)合规和监管,不同的地区的数据法规不一样,比如用户的隐私信息之类的(3)区域用户分区(4)不能做异地多活。一个原因是时间延迟问题,另外还是在于合规跟监管,不同地区的合规跟监管数据隐私保护的不一样,没办法做异地多活。
可以看下 Google 和 Facebook 的跨国数据中心,上面的图是 Google 的下图是 Facebook 的
跨国数据中心。主要部署在北美、欧洲、亚洲区。
::: hljs-center
:::
主要从应用场景维度看下几种架构的区别
像常见的冷备、双机热备、同城双活、异地双活、异地多活基本都是集合自己的业务场景及发展阶段对以上几种架构模式的应用。我们下面主要说下异地多活的集中模式。
::: hljs-center
:::
异地多活的落地可以概括为有三种大的模式,业务定制型异地多活、业务通用型异地多活、业务存储型异地多活。
::: hljs-center
:::
简单来说,业务定制型异地多活,就是按照业务的优先级进行排序,优先保证核心业务异地多活。然后基于核心业务的流程和数据,设计定制化的异地多活架构。但是 A 业务做的方案,并不能直接用到 B 业务上。比如说电商业务做的双活,不能用到社交的业务上,架构的方案并不通用。如下图中的示意图:
这种模式的优点就是:对基础设施没有强要求,例如机房部署、存储系统、时延等,一般是部署在远距离的两个城市,可以支持区域级别故障处理。缺点也比较明显,不通用,每个业务都需要单独来做异地多活,业务需要改造。难扩展,核心业务如果有重大变化,异地多活方案需要重新设计。
::: hljs-center
:::
这种方式一般是通过配套服务来支持异地多活。相对于业务定制型架构,一般无需按照优先级排序来挑选某些业务实现异地多活,只需要判断业务是否能异地多活,当然,业务实际落地的时候可能会有阶段或者灰度过程,并不是一步到位。这种架构的优缺点:
机房距离较远的时候,RTO 比较大,可能达到分钟级。异地多活基础理论是 Base,一定时间内达到最终一致,这个时间范围可能会较长,有可能会达到分钟级。
示意图
「案例」淘宝的单元化架构把业务分成很多个单元,每个业务绝大部分请求都可以在本单元内完成。不同的用户划分到不同的单元。除了单元还有个中心点。比如库存信息,全量的商品及卖家数据。再把数据复制到各个单元去。
示意图
【单元】单元(即单元化应用服务产品层的部署单元),是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及分配给这个单元的数据。单元化架构就是将单元作为部署的基本单位,在全站所有机房中部署多个单元,每个机房内单元数目不固定,任一单元均部署系统所需的全部应用,数据则是全量数据按照某种维度划分后的一部分。
::: hljs-center
:::基于业务通用性架构去做,有的业务不能满足 base 理论,就不能实现异地多活。那有没有一种方法,与业务不强相关,实现多活的架构设计呢?答案肯定是有的,从存储系统来实现,采用本身已经支持一致性的存储系统,实现存储通用型异地多活。
存储通用型异地多活架构方案的优点就是天然支持异地多活,业务除了切换存储系统外,其他基本不做改造。也不需要分析自己的业务场景、优先级。
缺点就是
(1)需要分布式一致性的存储系统支持。目前这样的存储系统可选不多,例如 zookeeper、etcd、OceanBase。实际上 zookeeper、etcd 不适合存储大量数据的。
(2)对机房部署有强要求,如果实现异地多活,只能采用近邻部署。分布式一致性框架,是需要通过协议通信的,这个对性能跟速度要求是有要求的,如果是分布式存储系统之间的节点,通信性能很差的话,那么会导致这个系统的读写性能会很差,就满足不了业务需求了。
「案例」 蚂蚁的 OceanBase 目前为止,OceanBase 是比较典型的一个分布式存储,而且是真正落地的一个分布式一致性存储系统。简单理解 OceanBase 就是一个基于 Paxos 算法来实现的分布式一致性存储系统。【参考官方介绍】
如上图,简单理解:
(1) Zone 是一个机房内的一组服务器,包含多台 OceanBase 数据库服务器(OBServer), 一般会把数据的多个副本分布在不同的 Zone 上,可以实现单个 Zone 故障不影响数据库 服务。
(2)每台 OBServer 包含 SQL 引擎、事务引擎和存储引擎,并服务多个数据分区,其中,每 个 Zone 有一台 OBServer 会同时使能总控服务(RootService),用于执行集群管理、服 务器管理、自动负载均衡等操作。
(3)OBServer 上会运行 SQL 引擎、事务引擎和存储引擎,用户的 SQL 查询经过 SQL 引擎 解析优化后转化为事务引擎和存储引擎的内部调用。
(4)OceanBase 数据库还会执行强一致的分布式事务,从而在分布式集群上实现数据库事务 ACID。(参考链接 :https://zhuanlan.zhihu.com/p/41139701)
参考下图理解,部署上一般要求 2 近 1 远,距离相近的两个城市,每个城市的机房都要部署 2 个 Zone,较远的城市部署一个 Zone.
「案例」蚂蚁的 LDC 架构结合淘宝单元化的架构+OceanBase
示意图
如上图,简单理解:
RZone(Region Zone):部署按用户维度拆分 的关键业务系统。核心业务和数据单元化拆分,每个单元内尽量调用闭环, 拥有自己的数据,能完成所有业务。一个可用区可以有多个 RZone。
GZone(Global Zone):部署未按用户维度拆分的系统,全局只有一份,被 RZone 依赖,提供不可拆分的数据和 服务,如配置型的业务。数据库可以和 RZone 共享,多租户隔离,全局只有一组,可以配置流量权重。
CZone(City Zone):部署未按用户维度拆分的系统,被 RZone 高频访问 ,解决跨域通信延时问 题。为了解决异地延迟问题而特别设计,适合读多写少且不可拆分的业务。以城市为单位部署的单元,一般每个城市一套应用和数据,是 GZone 的只读副本。
可以自行看下支付宝的案例介绍。(支付宝案例链接:https://www.sohu.com/a/406634738_99940985)
::: hljs-center
:::
从应用场景和实现成本上看下三种模式各有优缺点
::: hljs-center
:::
大厂一般常用的方案是通用型的技术方案。我们重点说下业务通用性的架构上的一些关键实现。
::: hljs-center
:::
主要是负责将用户的请求流量分配到对应的单元,例如蚂蚁的 Spanner。Spanner 是蚂蚁金服的七层网络代理 ,承载了蚂蚁金服所有的业务流量,包括支付宝 App、Web、商户等的终端访问。
如下图,用户通过蚂蚁金服的网络入口进来,通过多协议接入,到 LVS 和 Spanner,Spanner 作为统一七层网关把请求分发给后面的应用。在 Spanner 上有很多业务逻辑、协议支持,比如 TLS 1.3、QUIC、HTTP 以及蚂蚁自研的协议等。蚂蚁的所有业务,包括支付宝钱包、其他页面都是通过这个入口进来。
下图是 spanner 在三地五中心架构中的流量调度的场景,也可以发现,通过流量调度可实现:
::: hljs-center
:::异地多活架构下的路由中心,一般分三层。第一层是判断决定访问哪个机房或单元。第二层是在服务间调用的时候,来判断请求应该到哪个单元。第三层是到访问数据层,最后一层的兜底,决定访问到哪个 DB.
结合蚂蚁的架构,看下路由情况
【入口流量路由】
箭头1:对于应该在本 IDC 处理的请求,就直接映射到对应的 RZ 即可;
箭头2:不在本 IDC 处理的请求,Spanner 可以转发至其他 IDC 的 Spanner。
复制代码
【服务路由】
RPC调用、MQ的一些场景,有些场景来说,A 用户的一个请求可能关联了对 B 用户数据的访问,比如 A 转账给 B,A 扣 完钱后要调用账务系统去增加 B 的余额。这时候就涉及到:
箭头3:跳转到其他 IDC 的 RZone;
箭头4:跳转到本 IDC 的其他 RZone。
复制代码
【数据路由】
RZ 访问哪个数据库,是可以配置的,对应图中箭头 5。
(Data Replication Center):数据复制中心,主要是支持异构数据库实时同步,数据记录变更订阅服务。为业务跨域实时同步、实时增量分发、异地双活、数据双向同步、数据巡检、redis invaild 等场景提供支持。可以参考 otter 的架构设计。
单机房同步
如上图所示:
数据 on-Fly,尽可能不落地,更快地进行数据同步。(开启 node loadBalancer 算法,如果 Node 节点 S+ETL 落在不同的 Node 上,数据会有个网络传输过程)。Node 节点可以有 failover / loadBalancer。
异地多活同步
如上图所示:
数据涉及网络传输,S/E/T/L 几个阶段会分散在 2 个或者更多 Node 节点上,多个 Node 之间通过 zookeeper 进行协同工作 (一般是 Select 和 Extract 在一个机房的 Node,Transform/Load 落在另一个机房的 Node)。
Node 节点可以有 failover / loadBalancer. (每个机房的 Node 节点,都可以是集群,一台或者多台机器)。
::: hljs-center
:::DAL 是 proxy 型的数据库中间件,支持 mysql 协议。在多活项目中,DAL 责无旁贷扮演起保护数据正确性最后一道防线的角色。
对于个别一致性要求很高的应用,一般提供了一种强一致的方案,比如饿了么的架构中的 Global Zone,Globa Zone 是一种跨机房的读写分离机制,所有的写操作被定向到一个 Master 机房进行,以保证一致性,读操作可以在每个机房的 Slave 库执行,也可以 bind 到 Master 机房进行,这一切都基于数据库访问层(DAL)完成,业务基本无感知。
::: hljs-center
:::负责 Zone 的配置和容灾切换,例如 RZone 的业务范围,Zone 访问哪些数据库等。
::: hljs-center
:::服务多机房的发布。基于流量调度,完成 Zone 的蓝绿发布、灰度发布等。
::: hljs-center
:::快速新建一个完整的单元,包含机器搭建、基础设施搭建,服务部署等,目前基本都是基于容器技术实现的。
::: hljs-center
:::
在实际的落地过程中,还是有一些通用的架构设计方法来做参考。
::: hljs-center
:::完美是优秀的敌人,不能过于追求完美。在落地异地多活的时候,一般要遵守 3 个原则
(1)只保证核心业务。不同业务的数据特性不同,无法全部做到异地多活
(2)原则上只能做到最终一致性。复制肯定有时间窗口,抛弃实时一致性的想法。可以了解下【PACELC 理论】
(3)只能保证绝大部分用户。不能为了 0.01%的用户,影响到 99.99%的用户。
::: hljs-center
:::(1)业务定级
将业务按照某个维度进行优先级排序,有限保证Top3业务异地多活。一般定级的方向,可以从访问量、核心场景、收入来源看。
复制代码
访问量:登录>注册>修改密码核心场景:交易>社区收入来源:订单>搜索>编辑
(2)数据分类
分析TOP3中的每个业务的关键数据特点,将数据分类。
复制代码
数据是否可丢失,例如不可丢失(账户余额、订单)、可丢失(tocken、session)
数据是否可恢复,例如:用户恢复,系统提供恢复(密码找回)、内部恢复(例如编辑和运营重发)
(3)数据同步
针对不同的数据分类设计不同的数据同步方式。
复制代码
(4)异常处理
针对极端异常的情况,考虑如何处理,可以是技术手段,也可以是非技术手段。
复制代码
体验不好优于无法体验。比如数据短时间不一致,数据暂时无法获取。
少量用户损失,可以用钱解决。适当补偿优惠券。
::: hljs-center
:::::: hljs-center
:::下图是当前得物双活架构的业务示意图,包含了路由中心、DRC、DAL、配置中心等基础设施。
如图所示,用户在 app 发起请求后,客户端会先根据缓存的信息,判断该用户应该访问到哪台 SLB,然后 SLB 将请求转发到 DLB,DLB 会根据最新的路由规则,判断该用户是否属于本单元,如果是继续在本单元流转,如果不是,将请求转发到相应单元。如图中绿色请求所示,该用户实际规则应该路由到 B 机房,实际请求到 A 机房后,在 DLB 层也会将请求转发到 B 机房。应用服务注册的时候会标记自己的地址、服务类型。以便通过 RPC 服务间调用的时候进行路由。
在异地双活落地的过程中,重点说下需关注的几个点。
::: hljs-center
:::
从业务角度分析,最主要的是数据拆分。每个单元有部分用户的数据,用户尽可能地在本单元完成所有的行为操作。对于非用户维度的数据,部署在中心单元(机房),向单元机房做单向同步。为了灾备,用户维度的数据,单元机房和中心机房之间会双向同步。
数据架构示意图
按照业务的拆分规则,单元模式的数据,不同的用户会在不同的单元进行写入。单元和中心之间会双向同步。另外一种是中心模式的数据,这部分数据在中心写,全量同步到单元。可在单元进行访问。如果当前库既有单元模式的物理表又有中心模式的物理表,不建议混合在一起,最好进行拆分。
单元化模式:两边都会写入,双向进行同步,保证两边都有全量数据。保证在流量切流后,用户访问数据不受影响。
::: hljs-center
:::
还有一种是仅在中心部署的,比如库存数据,有强一致性要求,只在中心部署。数据的同步是通过 DRC 来完成的。
主要是通过 rpc 框架,让开发者不需要关心调用服务的细节。provider 将自己的服务,注册到注册中心,consumer 从注册中心拉取服务,并进行消费调用。在 rpc 框架内部,缓存了路由策略。可以直接在 consumer 获取服务时,根据规则进行筛选。让服务间的调用较简单。而且也提高了路由调度的灵活性。比如机房就近调用,单元化路由调用等。这也是上述 LDC 路由中的第二层路由。
一般的单元化规则:
(1)哪些用户属于哪个单元
(2)哪些应用属于单元
复制代码
但实际应用中,还有比较复杂的场景,从应用场景上,目前主要是分为三种:普通服务,单元服务,中心服务。
【普通模式】的服务就是没有做单元化改造的服务,没有单元的概念。服务间调用是就近调用,也就是本单元优先调用,如果本单元没有,会去中心调用。中心对普通服务的调用,也是直接调用中心的普通服务。
【单元模式】的服务是单元化路由服务,会根据路由 key(用户 ID),将请求进行路由到正确的单元。
【中心模式】的服务,尽管在中心和单元的注册中心都会注册,但请求最终只会路由到中心去。
做了双活之后,缓存失效的逻辑也会有一定变化。大部分应用,原缓存失效逻辑是:应用发起数据更新操作,先更新 DB 的数据,再进行缓存失效的处理,下次有请求的时候,数据从 DB 加载到缓存。
但做了双活之后,中心的数据发生变更,单元的缓存也要做失效处理。但单元的缓存失效不能直接依赖中心 DB 的变更消息。如果直接依赖中心 DB 的变更消息,单元的缓存失效有可能在单元 DB 变更之前失效,此时用户来访问,可能把旧数据写入缓存,导致数据不一致。
所以目前的解决方案是,通过 DRC,将中心的 DB 数据同步到单元,单元 DB 变更后,会通过 DRC 把 binlog 发送到 MQ,应用再去操作缓存失效或更新。
MQ 中间件也是需要做改造的,要保证消息能够落到正确的单元,并在正确的单元消费。
做双活前原有的的逻辑,大部分是接受消息后,对数据进行插入或更新操作。如果做了单元改造的库,部分数据已经根据相应策略划到对应单元写入,这时消息却在中心进行消费,这会导致两边双写,出现脏数据。这就需要 MQ 也有有路由的能力,让消息路由到正确的单元,不仅仅是依赖 RPC 框架或 DAL 层的路由限制。
目前的方案,消息会双向复制。根据消费方配置的订阅方式,进行订阅消费。
::: hljs-center
:::
(1)切流步骤
(2)容灾场景
单元机房出现故障,可以将流量切到中心新房
中心机房故障,当前的方案不能解决。可以在后续做到中心故障切换到中心备份环境,或者说,中心机房做逻辑机房,增强中心机房的抗灾能力。如下示意图
::: hljs-center
:::::: hljs-center
:::【RTO】(Recovery Time Objective),即恢复时间目标。主要指的是所能容忍的业务停止服务的最长时间,也就是从灾难发生到业务系统恢复服务功能所需要的最短时间周期。RTO 描述了恢复过程需要花费的时间。例如:假设在时间点 t1 启动恢复过程并且在时间点 t2 完成恢复,那么 RTO 就等于 t2-t1。RTO 值越小,代表容灾系统的数据恢复能力越强。RTO=0 就意味着在任何情况下都不允许目标业务有任何运营停顿。
【RPO】(Recovery Point Object)恢复点目标,指一个过去的时间点,当灾难或紧急事件发生时,数据可以恢复到的时间点,是业务系统所能容忍的数据丢失量。例如每天 00:00 进行数据备份,那么如果今天发生了宕机事件,数据可以恢复到的时间点(RPO)就是今天的 00:00,如果凌晨 3 点发生灾难或宕机事件,损失的数据就是三个小时,如果 23:59 发生灾难,那么损失的数据就是约 24 小时,所以该用户的 RPO 就是 24 小时,即用户最大的数据损失量是 24 小时。所以 RPO 指的是用户允许损失的最大数据量。这和数据备份的频率有关,为了改进 RPO,必然要增加数据备份的频率才行。RPO 指标主要反映了业务连续性管理体系下备用数据的有效性,即 RPO 取值越小,表示系统对数据完整性的保证能力越强。
可以通过下图来对比 RTO 和 RPO。
从图中不难看出,RPO 指标来自于故障发生前,而 RTO 指标来自故障发生后,两者的数值越小,就能有效缩短业务正常到业务过渡期的时间间隔,单一地提升 RTO 或 RPO 指标也可以缩减业务故障到过渡期的时间,具体从哪个指标上来改善,就要结合的实际情况分析,提升那个指标代价最小,效果更明显。
【WRT】(Work Recovery Time),工作恢复时间,指“系统恢复正常后,恢复业务所需的时间”,因为要进行各种业务检查、校验、修复。
【MTD】(Maximum Tolerable Downtime),最大可容忍宕机时间,等于 RTO + WRT。
参考资料:李运华《从 0 开始学架构》《架构实战专栏》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。