设计业务异地多活架构

一、高可用架构三大核心原理

  1、FLP 不可能原理

    FLP Impossibility(FLP 不可能性)是分布式领域中一个非常著名的定理,定理的论文是由 Fischer, Lynchand Patterson 三位作者于1985年发表。其表示在基于消息传递的异步通信场景,即使只有一个进程失败,也没有任何一种确定性的算法能保证非失败进程达到一致性!

   (1)FLP 的三大限定条件

    从上面FLP的定义中可以提炼出三个限定的条件,分别是确定性协议、异步网络通信、所有存活节点。

      确定性协议:即Deterministic protocol,指给定一个输入,一定会产生相同的输出。也就意味着里面不能有随机算法,所有的内容都是确定的。

      异步网络通信:首先说同步通信,同步通信是指所有节点同时在线并且允许超时,即在一定时间范围内没有收到应答,就认为节点挂掉,就做异常处理;而异步通信是指没有统一时钟、不能时间同步、不能使用超时、不能探测失败、消息可任意延迟、消息可乱序的情况,也就是说如果没有应答,是不能判断是节点挂掉还是网络故障,再或者是其本身处理速度慢。

        所有存活节点:所有存活的节点必须最终达到一致性,其认为网络是正常的,哪怕只有一个节点异常,就不能达到所有节点一致性。

    特别需要注意的一点,FLP 只是说没有“确定性协议”,而不是说“没有任何协议”。

  (2)FLP 的不可能三角:

      Safety:系统中非故障节点达成了一致和合法的共识,又称 Agreement。

      Liveness:系统中非故障节点在有限的时间内能够达成共识,又称 Termination。也就是说不能无限等待。

      Fault Tolerance:协议必须在节点故障的时候同样有效。类似于CAP中的P。

    这三个不可能同时满足,只能满足其中两项:

      SL 系统:为了达成一致,不允许节点失败,因此无法保证 Fault Tolerance。但是在分布式环境下,如果完全不允许失败,系统的可用性和强壮性就不能满足业务需求。这里就是这个算法比较难理解的地方,实际上Safety和Liveness中的“非故障节点”是算法的一个限定,或者可以理解为这是人为来判断的,但是其它的节点实际上是没法通过程序来判断一个节点是“真的故障导致无法回应其它节点消息”,还是只是“节点处理慢了一些,导致暂时还没回应”。对于SL系统来说,假设有1个节点没有回应,这个时候其它节点无法判断这个节点是故障了还是只是处理慢了,如果都当成处理慢了,那就需要等待,就不满足liveness;如果都当成故障,但实际上只是处理慢了一点,那就不满足Safety。

      SF 系统:为了保证 Safety,需要无限等待,因此无法保证 Liveness。

      LF 系统:为了保证 Liveness,不能无限等待,因此无法保证 Safety。因为无限等待的节点的响应结果可能会影响投票等信息。

   (3)Paxos 与 FLP

     Paxos 违背了 FLP 么?从 FLP 的三大限定条件一一分析:

      确定性协议:由于 Paxos 可能出现 livelock,所以 Paxos是使用 Bully 算法、随机等方式选举 Leader,也可以随机延迟发起 proposer。从随机可以看出,其不满足确定性协议限制。

      异步网络通信:Paxos采取同步通信或者超时机制。可以看到其不满足异步通信限制。

      所有存活节点:Paxos 采取 Quorum 机制,也就是多数节点机制。可以看到,其不满足所有节点限制。

    由此可以看出, Paxos 并没有违背 FLP 定理,只是为了在工程落地时可以实现分布式一致性,突破了 FLP 的一些约束和限制,或者说放宽了 FLP 中的一些约束和限制。FLP是说在确定性协议、异步网络通信、所有存活节点这三个限定条件下,没有可以实现分布式一致性的算法,而Paxos从这三个限定条件的角度,都做了调整,也就是每一个限定条件突破了,所以总的来说,Paxos虽然实现了分布式一致性算法,但是并没有违反FLP

        

    Paxos 遵循的是 SF,因为在liveLock情况下,会造成无限循环的情况,就不满足 Liveness。

     (4)Paxos livelock:也就是活锁,两个节点相互拒绝的情况。

        

  2、CAP 定理

   CAP:一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

  (1)CAP 的三大限定条件:

    分布式:分布式,因为如果不是分布式的情况下,不可能发生网络分区。

    数据存储:通过复制来实现数据共享的存储系统,如果不是通过复制来实现数据共享,那就可能同时满足CAP。 

    同时满足:同时满足 CAP。也就是说在上述两个限定条件下,不可能同时满足CAP。

  (2)CAP 的不可能三角:

      一致性(Consistency):每次读取操作都会读取到最新写入的数据,或者返回错误。

      可用性(Availability):每次请求都会得到非错请求,但不保证返回最新的数据。

      分区容错性(Partition tolerance):系统在发生分区的时候继续提供服务。

    根据不可能三角,可以得出以下三种系统:

      CA:为了达成数据一致性和系统可用性,不允许分区。在分布式系统中,不允许分区,那么系统的可用性和健壮性会不能满足业务需要。

      CP:系统分区的时候保证一致性,但无法保证可用性。

      AP:系统分区的时候保证可用性,但无法保证数据一致性。

  (3)CAP 细节

    CAP只是一个原理,为了在数学上可以证明,其省略了很多的细节问题,但是这些细节问题在我们落地时是非常关键的点。

    复制延迟:

      理论上 CAP 是忽略网络延迟的,但是实际在工程落地时,不可能没有延迟,哪怕一毫秒的延迟,那也是存在延迟。

      所以在实际工程落地时,可以使用PACELC猜想,如果发生了分区,则从可用性和分区一致性上二选一;如果没有分区,则从延迟和最终一致性中二选一。

      比较类似的是,FLP 也是假设网络一切正常,没有延迟也没有分区。

         

    描述粒度:

      我们通常在描述时会说这个系统是AP还是CP,但是实际上CAP 关注的是单个数据,不是整个系统,一个系统中数据可以有的符合 CP,有的符合 AP,而不需要将整个系统必须设计为CP或AP。

      那么为什么说Paxos是一个CP系统,这是因为Paxos中所有的数据都是一种处理方式,都是CP的,所以说Paxos是一个CP系统,这和我们的业务系统是不一致的,因为业务系统可能会有多种情况的数据。

        

    更多:

      正常运行情况下,可以满足 CA,但是实际上有很小的时延。

      放弃 != 无为,需要为分区恢复后的数据恢复和业务恢复做好准备,也就是说如果是AP,那么分区恢复后,需要重新保证数据一致性。

      CAP 的 CA 和 ACID 的 CA 定义完全不同,两者适应的领域也不同。

  3、BASE 理论

    BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency),核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。

      Basically Available:读写操作尽可能的可用,但写操作在冲突的时候可能丢失结果,读操作可能读取到旧的值。这样对业务是有影响的,因为Base理论本身就不强调对业务完全没有影响,而是影响在可容忍范围内。

      Soft State:没有一致性的保证,允许系统存在中间状态,而该中间状态不会影响系统整体可用性,而不是说对任何业务都不影响,这里的中间状态就是CAP 理论中的数据不一致。

      Eventually Consistency:如果系统运行正常且等待足够长的时间,系统最终将达成一致性的状态。

    最终一致性 & 强一致性:

      下面两张图是最终一致性和强一致性的描述,例如左侧的图是最终一致性,由于复制延迟,不同的客户端读取不同数据,但是只要保证在一段时间后数据一致即可;右边的图表示的是强一致性,读取数据要加锁,需要等待数据同步完成才可以处理,但是在分布式环境下,需要加分布式锁,这种跨数据中心的分布式锁,性能非常低。

        

    BASE 是 CAP 中 AP 方案的延伸,考虑了网络时延和系统恢复正常后的状态。

  4、BASE、CAP、FLP 落地

    在实际项目落地时,首先要考虑是否需要强一致性,如果不需要,直接按照Base理论设计系统即可,如果需要强一致性,那么再看是否需要多副本,如果需要,则选用分布式一致性算法来实现,例如Paxos、ZAB、Raft等,如果不需要多副本,则使用单点读写即可,但是单点读写也要做好数据备份,例如10分钟备份一次,但是如果发生系统异常,可能会发生部分数据丢失,要在可容忍的范围内做数据备份。

         

二、用 FMEA 方法排除架构隐患

  在上一节说了FLP、CAP、BASE,这些理论可以用来指导我们设计高可用的系统架构,当架构设计出来后,如何确定架构确实实现了设计前的要求,那么就可以使用FMEA来排查。

  1、FMEA 介绍

    定义:FMEA(Failure mode and effectsanalysis,故障模式与影响分析)又称为失效模式与后果分析、失效模式与效应分析、故障模式与后果分析等。

    历史:FMEA 最早是在美国军方开始应用的,20世纪40年代后期,美国空军正式采用了 FMEA。二十世纪60年代,在开发出将宇航员送上月球并安全返回地球的手段的同时,FMEA 得到了初步的推动和发展。二十世纪70年代后期,福特汽车公司在平托事件之后,出于安全和法规方面的考虑,在汽车行业采用了 FMEA。

    作用:FMEA 之所以能够在这些差异很大的领域都得到应用,根本原因在于FMEA 是一套分析和思考的方法,而不是某个领域的技能或者工具。FMEA 并不能指导我们如何做架构设计,而是当我们设计出一个架构后,再使用FMEA 对这个架构进行分析,看看架构是否还存在某些可用性的隐患。

    FMEA 详解:Failure:假设系统某些组件或者模块出现故障。Mode: 故障发生的方式、可能性。Effect :故障的影响。Analysis:分析系统的可能反应,以及如何改进。

        

     FMEA 什么阶段应用:

         

     案例 - 电子门锁 FMEA 分析:这个案例很简单也比较典型,具体就不多描述了,但是有个问题,买了电子锁还让用户带钥匙会不会影响用户的使用体验?这个确实是会影响,但是带钥匙和不能进家门相比,还是需要这么做的。

        

  2、FMEA 技巧

    FMEA 应用步骤:

      (1)给出初始的架构设计图,一般是系统架构图和部署架构图。

      (2)假设架构中某个 Role 发生故障,然后分析此故障对系统功能造成的影响。

      (3)根据分析结果,判断架构是否需要进行优化。这里需要说明的是,就断分析出存在问题,也不一定需要优化,还是需要进行判断的,因为并没有一个完美的架构。

      FMEA可以用来优化架构,那么客户端和前端需要使用FMEA来优化架构么?实际上是不需要的,因为前端架构一般都是一个应用,虽然应用内部可能有多个模块,但是一旦一个模块不能用,整个App就会直接退出;另一方面前端和客户端也不会像后端一样做一些冗余或者数据倒换,一旦异常就会退出App。

         

    FMEA 分析维度

         

    FMEA 技巧详解:

     (1)业务功能:用户角度划分的业务相关的功能点。

        从用户角度而不是系统角度。例如:对于一个用户管理系统,使用 FMEA 分析时 “登录”“注册”才是功能点,而用户管理系统中的数据库存储功能、Redis缓存功能不能作为 FMEA 分析的功能点。

     (2)故障模式:系统会出现什么样的故障,包括故障点和故障形式。

        故障模式并不需要给出真正的故障原因,只需要假设出现某种故障现象即可。故障模式的描述要尽量精确,多使用量化描述,避免使用泛化的描述。例如,推荐使用“MySQL响应时间达到3秒”,而不是“MySQL 响应慢”

     (3)故障影响 :故障发生后业务功能具体会受到什么影响。

        常见的影响有:功能点偶尔不可用、功能点完全不可用、部分用户功能点不可用、功能点响应缓慢、功能点出错等。故障影响也需要尽量准确描述。例如,推荐使用“20%的用户无法登录”,而不是“大部分用户无法登录”。

     (4)严重程度:从业务角度看故障的影响程度。

        一般分为“致命/高/中/低/无”五个档次。

        严重程度按照这个公式进行评估:严重程度 = 功能点重要程度 × 故障影响范围 × 功能点受损程度。例如:登录功能比修改用户资料要重要得多,80%的用户比20%的用户范围更大,完全无法登录比登录缓慢要更严重。

        团队讨论确定,包括业务、开发、运维等一起讨论,但是要避免业务方有意无意夸大严重程度。如果争执不下,架构师拍板。

     (5)故障原因:导致故障现象出现的原因。

        故障现象相同,对业务影响相同;故障原因不同,发生概率、检测手段、处理措施不同。

        例如:1. 发生概率:“MySQL bug”的概率要远远低于“没有索引”导致查询慢。2. 检测手段:磁盘坏道导致 MySQL 响应慢和慢查询的检测手段不同。3. 处理措施:磁盘坏道要换机器,慢查询要优化索引。

     (6)故障概率:某个具体故障原因发生的概率。

        一般分为“高/中/低”三档即可,几个特别注意的现象:1. 硬件(硬件随着使用时间推移,故障概率会越来越高,例如,新的硬盘和3年的硬盘。)2. 开源系统(成熟的开源系统 bug 率低,版本3.0比版本0.3要成熟;已经有使用经验和第一次使用。)3. 自研系统(和开源系统类似,成熟的自研系统故障概率会低,而新开发的系统故障概率会高。)

     (7)风险程度:综合严重程度和故障概率来一起判断某个故障的最终等级。

        风险程度 = 严重程度 × 故障概率。某个故障影响非常严重,但其概率很低,最终来看风险程度就低。例如:“某个机房业务瘫痪”对业务影响是致命的,但如果故障原因是“地震”,如果机房在广州概率就很低,如果机房在东京,概率就高很多。

       (8)已有措施:针对具体的故障原因,系统现在是否提供了某些措施来应对。

        常见措施有:1. 检测告警(检测故障并告警,系统自己不针对故障进行处理,需要人工干预。)2. 容错(检测到故障后,系统能够自行应对。例如:Hadoop集群。)3. 自恢复检测到故障后,系统能够自己恢复。例如,踢出故障的容器节点,创建新的容器。)

     (9)规避措施:为了降低故障发生概率或者故障影响而采取的一些措施。

        可以是技术手段,也可以是管理手段。例如:1. 技术手段:为了避免新引入的 MongoDB 丢失数据,在 MySQL 中冗余一份。2. 管理手段:为了降低磁盘坏道的概率,强制统一更换服务时间超过2年的磁盘。

     (10)解决措施:为了能够解决问题而采取的一些措施。

        一般都是技术手段,例如:1. 为了解决密码暴力破解,增加密码重试次数限制。2. 为了解决拖库导致数据泄露,将数据库中的敏感数据加密保存。3. 为了解决非法访问,增加白名单控制。如果某个故障既可以采取规避措施,又可以采取解决措施,优先选择解决措施。

     (11)后续规划:针对 FMEA 分析表格,查漏补缺,优化系统架构。

        具体步骤:第一步:排序,按照风险程度的评估结果排序;第二步:制定改进方案;第三步:对改进后的方案重新应用 FMEA 评估。

        技巧:1. 技术手段、管理手段都可以;2. 检测、规避、解决手段都可以;3. 需要考虑成本。例如:地震、敏感数据泄露、MongoDB 断电丢失数据,分别如何处理。

    FMEA 落地技巧:

      抓住核心:优先针对核心场景进行分析。

      分工合作:可以安排给初级架构师或者高级开发人员,锻炼架构思维。

      适可而止:严重程度为高的必须解决,严重程度为中的做好检测和告警。

  3、FMEA 案例

    例如在学生管理系统中,使用Mysql和Memcached。

        

    FMEA 分析 - 登录:

        

    FMEA 分析 - 注册:

         

      这里有个问题,就是不同的故障原因,可能由于功能点的影响、严重程度、概率、风险程度等影响,后续的规划是不同的。

    FMEA 优化后的架构:

        

三、业务级灾备架构设计

  1、同城多中心架构

    同城双中心基本架构如下图所示:

        

    关键特征:相同城市,相距 50km 以上(因为小于50km有可能在异常情况下造成双机房同时故障,例如同城同区域断电等);光纤互联;机房间网络延时 < 2ms。

    同城双中心架构本质:同城双中心可以当做一个逻辑机房;可以应对机房级别的灾难。

    同城双中心应用技巧 - 多光纤通路:由于同城双机房部署的时候将其视为同一个逻辑机房,那么整个集群有可能因为一个机房故障导致不可用,如下图中的Redis Sentinel集群,如果IDC-1故障,就会导致Redis Sentinel集群不可用,所以需要采用多光纤通路,尽量保证双机房网络正常。但是如果特别极端情况下导致所有光纤故障,这种情况可以采用第三个机房,只不过第三机房只部署负责集群选举的集群即可。

        

    同城三中心:

      这种方案很少采用,因为从成本上高很多,但是从高可用上来说,相比同城双机房并不会提升很多。另外需要注意的是,同城三中心表示的是三个机房都是相同的部署,和上面讲得双中心再加一个选举集群的机房是有本质区别的。

        

  2、跨城多中心架构

    跨城双中心基本架构:

      关键特征:不同城市;光纤互联。

      应用场景:城市级别灾备;用户分区;异地多活

        

    (1)跨城双中心落地方案 - 近邻城市:

      选择两个近邻城市部署,例如广深、京津、沪杭;机房延时 < 10ms,可以当做同一逻辑机房;

      可以避免城市级别的灾难,但是无法避免区域性灾难;可以做异地多活,但不做用户分区。

        

   (2)跨城双中心落地方案 - 远端城市

      选择两个远距离的城市;机房延时 > 30ms,不能当做同一逻辑机房;

      可以避免城市级别和区域级别的灾难;适应异地多活架构、分区架构。

        

    (3)跨城多中心

       可以用来做用户分区、就近接入、异地多活,但是这种一般是巨头专属,因为用户量不足千万或上亿的情况,一般不需要这么做,成本太高。

        

   (4)OceanBase 官方推荐架构

      OceanBase 官方推荐采用2近(10ms)1远(30ms)的IDC部署,其可以应对城市级别故障,是最高可靠性架构,但是也是成本最高。

        

  3、跨国数据中心架构

    全球部署;合规和监管

    跨国数据中心最主要的是要合规和监管,因此其可以区域用户分区;不会做异地多活

         

  4、业务灾备架构对比

        

四、异地多活架构的三种模式

  1、业务定制型异地多活

    业务定制型异地多活:按照业务的优先级进行排序,优先保证核心业务异地多活 ;基于核心业务的流程和数据,设计定制化的异地多活架构。

    优点:对基础设施无强要求,例如机房部署、存储系统、时延等,但是一般部署在远距离的两个城市,可以支持区域级别故障处理。

    缺点:不通用,每个业务都需要单独来做异地多活,业务需要改造;难扩展,核心业务如果有重大变化,异地多活方案要重新设计。

        

    阿里游戏异地多活设计:

      业务分级:登录、支付。

      数据分类:登录关键数据:session、角色 ID、账号密码;支付关键数据:支付本身依赖支付宝、微信,支付后的点券元宝等是游戏管理的

      数据同步:session:不同步,重复生成;角色 ID:全局唯一,消息队列同步 + 算法重复生成;账号密码 & 支付:第三方管理,无需处理。

      异常处理:人工修复;礼包、代金券补偿。

        

     阿里游戏异地多活架构优化如下图所示:

      左图是早期的架构有两个机房,但是A机房是主库,B机房是从库,所有的写操作都放到A机房的主库,写完成后将数据同步到两个机房的从库,这样就会存在主库单点问题,同时还存在跨机房同步时延问题。

      右图是异地多活架构,在两个机房中都有自己的主库,通过业务层进行数据同步;并且采用二次读取,即如果从A机房读取不到数据,可以从B机房做二次读取;然后还采用算法可重复生成全局唯一数据。

        

     阿里游戏异地多活设计核心 - RoleID:一般情况下,使用三方登录后,都会返回一个RoleID,都不会返回真正的用户ID,例如下面王者荣耀的例子,使用微信登录后,微信返回的也是一个RoleID,并不是微信的用户ID,这是为了防止游戏厂家通过用户ID找到这个用户将用户洗为官方用户。

         

    阿里游戏异地多活设计核心 - 算法生成 RoleID:在最早期的时候直接使用用户ID作为RoleID,就造成了游戏厂家直接在论坛找到用户将用户洗为官方用户,那么后来就使用了自增ID,但是在做异地多活时,这种自增ID就成为了设计的难点,因为其需要单点的自增ID生成器,后来使用了MD5加密用户ID的方式(用户ID会加盐),但是由于自增ID的接口已经上线,就需要兼容这种情况,那么最终采用了CRC32的方式解决了。

      这里说一下CRC32算法,我们知道CRC32是会重复的,但是对于游戏业务来说,有百万用户已经是非常难得了,更别说千万用户了,对于千万用户的场景来说,CRC32重复的概率大概在万分之几,概率已经非常低了,如果有少数重复的问题,可以使用CRC32二次处理即可。因此算法还要根据场景灵活运用,不要死记硬背。

         

  2、业务通用型异地多活

    通过配套服务来支持异地多活,无需按照业务优先级排序来挑选某些业务实现异地多活,只需要判断业务是否能异地多活。

    优点:对硬件基础设施无强要求,例如机房部署、存储系统、时延等,一般部署在远距离的两个城市,可以支持区域级别故障处理。业务基本不用改造,只需判断业务是否支持 BASE,支持就可以异地多活,不支持就单点部署。

    缺点:配套服务复杂,包括流量调度、容灾切换、建站平台、配置管理等;存在全局单点业务,例如库存、卖家等相关业务;机房距离较远的时候,RTO 比较大,可能达到分钟级。

         

     (1)业务通用型案例 - 淘宝的单元化架构

       LDC(Logic Data Center)架构,又称为单元化架构,是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及分配给这个单元的数据。将用户分配到不同的单元中处理即可。

      但是LDC中海油一些不能做异地多活的系统,统称为中心,例如库存、卖家、长尾数据等,不过可以将全量卖家数据和区分好的用户数据同步到不同的单元即可。

        

    (2)业务通用型案例 - 蚂蚁的 LDC 架构

      蚂蚁的LDC架构是基于淘宝的LDC架构演进而来的。

      RZone(Region Zone):部署按用户维度拆分的关键业务系统。核心业务和数据单元化拆分,拆分后分片均衡,单元内尽量自包含(调用封闭),拥有自己的数据,能完成所有业务。一个可用区可以有多个 RZone。

      CZone(City Zone):部署未按用户维度拆分的系统,被 RZone 高频访问 ,解决跨域通信延时问题。为了解决异地延迟问题而特别设计,适合读多写少且不可拆分的业务。 一般每个城市一套应用和数据,是 GZone 的快照。

      GZone(Global Zone):部署未按用户维度拆分的系统,被 RZone 依赖,提供不可拆分的数据和服务,如配置型的业务。数据库可以和 RZone 共享,多租户隔离,全局只有一组,可以配置流量权重。

        

     (3)LDC 路由:三次路由

        

       Spanner 是蚂蚁基于 Nginx 自研的反向代理网关,Nginx是基于请求路由的,而Spanner是基于业务路由的、

      一次路由:箭头1:对于应该在本 IDC 处理的请求,就直接映射到对应的 RZ 即可;箭头2:不在本 IDC 处理的请求,Spanner 可以转发至其他 IDC 的 Spanner。

      二次路由:有些场景来说,A 用户的一个请求可能关联了对 B 用户数据的访问,比如 A 转账给 B,A 扣完钱后要调用账务系统去增加 B 的余额。这时候就涉及到:箭头3:跳转到其他 IDC 的 RZone;箭头4:跳转到本 IDC 的其他 RZone。

      数据路由:RZ 访问哪个数据库,是可以配置的,对应图中箭头5。

    (4)LDC 容灾

        

       一级容灾:RZone 自容灾,例如 RZ0A 挂掉,Spanner会将所有流量会分给到RZ0B。

      二级容灾:如果 RZ0A 和 RZ0B 都挂掉,但数据库没挂掉,直接新建 RZone 代替。需要建站平台快速新建整个 RZone。

      三级容灾 - 异地多活:如果 IDC-1 挂掉,则在 IDC-2 新建 RZone,然后读写 IDC-2 的数据库。这种情况可能丢数据,RTO 是分钟级,所以官方要求,不能接受这个RTO 就不要做切换,也就不支持异地多活。

    (5)LDC 蓝绿发布

      Step1:发布前,将“蓝”流量调至0%,对“蓝”的所有应用整体无序分2组发布。

      Step2:“蓝”引流1%观察,如无异常,逐步上调分流比例至100%。

      Step3:“绿”流量为0%,对“绿”所有应用整体无序分2组发布。

      Step4:恢复日常运行状态,蓝、绿单元各承担线上50%的业务流量。

        

    单元化架构的核心 - 配套服务

      流量调度:负责将用户请求流量分配到对应的 RZone,例如蚂蚁的 Spanner。

      配置中心:负责 Zone 的配置和容灾切换,例如 RZone 的业务范围,Zone 访问哪些数据库等。

      建站平台:快速新建一个完整的 Zone,目前基本都是基于容器技术来实现。

      发布平台:基于流量调度,完成 Zone 的蓝绿发布、灰度发布等。

  3、存储通用型异地多活

    采用本身已经支持分布式一致性的存储系统,架构天然支持异地多活。

    优点:架构天然就支持异地多活,业务除了切换存储系统外,其它基本不用改造。

    缺点:需要分布式一致性的存储系统支持,目前这样的存储系统可选不多,例如 ZooKeeper、etcd、OceanBase,而ZK和etcd并不能大规模存储数据;对机房部署有强要求,如果要实现异地多活,只能采用近邻部署

        

    蚂蚁 OceanBase 简介

     OceanBase 数据库是阿里巴巴和蚂蚁集团不基于任何开源产品,完全自研的原生分布式关系数据库软件,在普通硬件上实现金融级高可用,首创“三地五中心”城市级故障自动无损容灾新标准,具备卓越的水平扩展能力,全球首家通过 TPC-C 标准测试的分布式数据库,单集群规模超过 1500节点。 产品具有云原生、强一致性、高度兼容 Oracle/MySQL 等特性, 承担支付宝 100% 核心链路,在国内几十家银行、保险公司等金融客户的核心系统中稳定运行。

    1. Zone 是一个机房内的一组服务器,包含多台 OceanBase 数据库服务器(OBServer),一般会把数据的多个副本分布在不同的 Zone 上,可以实现单个 Zone 故障不影响数据库服务。

    2. 每台 OBServer 包含 SQL 引擎、事务引擎和存储引擎,并服务多个数据分区,其中,每个 Zone 有一台 OBServer 会同时使能总控服务(RootService),用于执行集群管理、服务器管理、自动负载均衡等操作。

    3. OBServer 上会运行 SQL 引擎、事务引擎和存储引擎,用户的 SQL 查询经过 SQL 引擎解析优化后转化为事务引擎和存储引擎的内部调用。

    4. OceanBase 数据库还会执行强一致的分布式事务,从而在分布式集群上实现数据库事务ACID。

        

     OceanBase 三地五中心异地多活架构

      部署要求:2近(10ms)1远(30ms),两个IDC在相邻城市,一个机房在远端城市,相邻城市的两个IDC中,每个IDC部署两个Zone,远端城市IDC部署一个Zone,也就是整个集群五个Zone,这是因为OceanBase采用了Paxos算法,这样就需要使用多数节点来做集群选举。

      优缺点:可以应对城市级别的故障;无法应对区域级别故障,例如杭州和上海同时停电,因为相邻IDC故障会导致Paxos多数不可用;成本最高,至少三个机房,如果采用分区架构,每个分区都要按照三地五中心来部署,这是因为Paxos算法的原因,如果IDC距离远,会影响Paxos选举,但是可以采用分区内有相邻的两个IDC,远端城市IDC可以复用其他分区的IDC。

        

  4、异地多活架构模式对比

    业务定制型的最大缺点是不通用,业务通用型的最大缺点是需要有配套服务,而存储通用型的缺点是要求临近部署,且对机房数量和时延要求高。

         

五、业务定制型异地多活架构设计

  上面描述了异地多活的三种架构设计,但是业务通用型难度并不大,最主要的是需要投入人力去开发配套设施,这一套设施下来,可能需要一两百人研发两年,成本非常高;而存储通用型异地多活需要采购成熟的分布式数据库,成本也很高,所以业务定制型异地多活对于大多数公司和大多数业务来说是最合适的方案。

  1、异地多活 - 1个原理:CAP定理

      粒度:CAP 关注的粒度是数据,而不是系统,需要根据不同业务的数据特点来设计异地多活。

      延迟:CAP 是忽略网络延迟的 ,但工程落地不可能做到零延迟。C和A只能取1个是在发生分区的时候,正常运行情况下,可以同时满足 CA。放弃 != 无为,需要为分区恢复后做准备,包括人工修复数据。

      分区容忍:C和A只能取1个是在发生分区的时候,正常运行情况下,可以同时满足 CA。

      补救:放弃 != 无为,需要为分区恢复后做准备,包括人工修复数据。

  2、异地多活 - 3大原则

    原则一:只保证核心业务:不同业务的数据特性不同,无法全部做到异地多活。

         

    原则二:只能做到最终一致性:复制肯定有时间窗,抛弃实时一致性的幻想,PACELC 理论。

        

     原则三:只能保证绝大部分用户:不要为了0.01%的用户,而影响了99.9%的用户!

        

  3、异地多活 - 4个步骤

         

     业务分级:将业务按照某个维度进行优先级排序,优先保证TOP3 业务异地多活,可以按照访问量、核心场景、收入来源这三个维度进行评估。例如访问量来说登录>注册>修改密码,从核心场景来分析微信,聊天>朋友圈>摇一摇,从收入来源来分析酒旅业务,订单 >搜索>编辑

        

    数据分类:分析 TOP3 中的每个业务的关键数据特点,将数据分类。

      数据修改量:数据被修改的数量和频率,因为只有修改的数据才需要同步,包括新增、删除、修改。

      一致性:数据的一致性要求,最终一致性的就可以做异地多活,而强一致性的就很难做。例如:强一致性(余额、库存)、最终一致性(动态、兴趣)。

      唯一性:数据的唯一性要求,如果数据唯一,从异地多活的落地来说就会非常简单。例如:全局唯一(用户 ID)、可重复(昵称)。

      可丢失性:数据是否可丢失,如果允许丢失数据或者允许数据段时间不一致,对于落地异地多活架构来说也会简单很多。例如:不可丢失(账户余额)、可丢失(微博、密码)。

      可恢复性:数据是否可恢复,例如:用户恢复(微博)、系统提供恢复(密码找回)、内部恢复(例如编辑和运营重发)。

    数据同步:针对不同的数据分类设计不同的数据同步方式。

      多管齐下,“不择手段”,不要局限于存储系统同步!例如下图示例,可以通过数据库同步、消息队列、二次读取、回源读取、重新生成等方式。这里说明一下二次读取和回源读取的区别,二次读取是指先读取本IDC的数据,没有的话再读取其他IDC的数据,而回源读取是指请求自带IDC属性,可以直接从指定的IDC读取。

        

       数据同步技巧:

        

    异常处理:针对极端异常的情况,考虑如何处理,可以是技术手段或非技术手段。

      业务兼容:体验不好 优于 无法体验。数据短时间不一致,虽然业务有损,但是用户感官不严重,例如微博、朋友圈;数据无法获取,可以采用转账申请,支付核对中的友好提示。

      事后补偿:少量用户损失,用钱解决。礼包、红包;礼物、物品(暴雪炉石回档补偿);保险赔偿。

      人工修正:尽力而为,减少损失。人工订正数据,达到最终一致性;重要事情说三遍:日志、日志、日志。

  4、异地多活 - 5个技巧

    (1)消息队列同步:适合全局唯一的数据,因为可以覆盖;不适合余额之类的数据,因为数据修改无法做到幂等性。如下图所示,可以采用数据库主同步,消息队列辅助同步的方式,由于数据全局唯一,即使消息队列先到,数据库后到,也可以通过mysql的slave-skip-errors来处理。

        

     (2)库存拆分:可以将库存数据拆分到不同的IDC,如果一个IDC的库存售卖完,可以使用另外一个IDC的库存,如果其中一个IDC故障,那么另外一个IDC存在库存,仍然不影响业务。

        

     (3)事务合并

       这种就比较复杂一点,例如游戏充值购买场景,由于余额属于强一致性数据,因此当一个IDC故障时,可能余额数据没有同步过来,那么就不能动当前IDC的余额数据,那么就可以采用一个折中的方案,例如使用一个临时表,用户充值后将数据存入临时表,消费也是使用的临时表数据消费,待故障的IDC恢复后,将临时表数据同步到恢复好的IDC,该IDC将数据消费后,在同步其他IDC余额即可。

        

     (4)实时改异步:这种比较好理解,例如转账数据,本来是实时转账,那么有可能IDC故障,那么可以将转账数据发送到消息队列,然后不断轮询消息队列对故障的IDC内服务发起重试,一旦重试成功,则异步返回成功即可。

        

     (5)适当容忍:业务上稍微放开一些约束,例如:电话会议系统允许欠费也能发起会议,但是一般会设置一个阈值。

        

六、异地多活架构实战

(一)王者荣耀异地多活架构模拟设计

  1、王者荣耀业务背景

    业务数据:2020.11月公布数据,全年日均活跃1亿,注册玩家数6亿,最高同时在线100万。

    业务功能:登录(使用微信或者 QQ 账号登录游戏)、对战(例如匹配、排位、巅峰赛)、 商城(购买英雄、皮肤、道具等)、活动(领取各种奖励和道具)、社区(各种攻略,视频等)

    关键业务约束:登录用户才能对战;用户属于不同的区服,例如 Android 平台微信22区“刺客信条”,同一微信ID 可以加入多个区服,俗称“大号”、“小号”;不同区服用户可以一起对战。

  2、设计步骤

  (1)业务分级

    在王者荣耀的业务场景中(注册、登录、对战、商城、社区、活动),异地多活应该保证核心的登录、对战,因为对于游戏业务来说,核心的就是玩游戏,玩游戏的前提就是能登陆。

    那么就会有几个问题:新用户注册不了,玩不了游戏怎么办?商城直接决定了游戏收入,为啥这里不做异地多活?第一个问题是因为新用户本来就是新手,影响并不大;第二个问题是商城可以做异地多活,但是要看增加商城的异地多活后成本是否提高非常多,另外一方面,刚好在故障期间,有购买意愿并产生购买行为的用户并不多,并且对于游戏购买来说,用户的黏性非常强,一般当时买不了,在系统恢复后也会选择继续购买。

  (2)数据分类

    登录:依赖 QQ 和微信账号授权登录,本身无需登录信息;微信和 QQ 授权登录会返回给王者荣耀全局唯一 RoleID;王者荣耀只需要记录 RoleID 对应的区服信息,区服数据只会新增不会修改。

    加入对战:RoleID:登录后就不会变了;对战 ID:每次新建,全局唯一,不会修改;对战数据:和对战 ID 绑定,只会新建不会修改,例如对战过程、对战结果等。

  (3)数据同步

    登录:RoleID 和区服对应关系,只会新建不会修改,数据库同步即可。

    加入对战:RoleID:同登录;对战 ID:每次新建,全局唯一,不会修改,用算法生成,数据库同步即可;对战数据:和对战 ID 绑定,不会修改,数据库同步即可。

  (4)异常处理

    登录:微信和 QQ 挂了怎么办?直接挂公告:系统停服维护。玩家在某个区服开了小号,没同步到异地机房,玩不了怎么办?等系统恢复就可以玩了。

    加入对战:用户对战过程中系统挂掉怎么办?用户重新对战即可,原有对战数据作废。用户对战数据未及时同步到异地机房,用户看不到对战结果怎么办?等恢复了再看。

  3、王者荣耀异地多活架构示意图

    最终设计的简化版异地多活架构如下图所示,首先将机房分为南北方机房,可以实现就近接入,将服务器分为区服务器和对战服务器,由于区服务器存储的是RoleID和区的对应关系,只会新增不会变化,因此采用根据游戏分区双机房互为主备的方式做数据同步;对战服务器存储的是RoleID和对战ID,数据不会重复和变更,因此采用数据库双主的方式。

        

(二)视频会议异地多活架构模拟设计

  1、视频会议业务背景

    部署架构:某个视频会议系统,用户按照地理位置分为南方区和北方区用户,分别对应深圳机房和天津机房。

    业务功能:注册、登录、发起会议、加入会议、充值、创建群、用户资料管理。

    关键业务约束:登录用户才能参加会议;充值用户才能发起会议;余额不够不能发起会议。

  2、设计步骤

  (1)业务分级

    在该业务中核心业务是登录、发起会议、加入会议,因为视频会议的首要目的是开会,那么发起会议就是最主要的场景,另外一个就是加入会议,如果只能发起不能参会,那发起的会议也没有意义,另外业务要求只有登录才能参会,所以登录也是核心业务场景。

    基于上面的分析,可能会有以下几个问题:

      某个客户紧急情况下需要拉一个新用户来开会,注册不了怎么办?这种其实有很多种解决方案,例如借一个账号,或者可以从业务的角度放宽限制,可以由发起人给一个密码,不需要登录,只需要入会密码即可。

      某个用户改了密码未同步,此时发生故障,在异地机房登录失败怎么办?这种也有多种解决方案,例如可以使用手机号+验证码的方式登录等。

      没钱就不能开会,为何充值不是核心功能?实际上这种用户并不多,但是如果真的有这种用户,后面会讲如何处理。

  (2)数据分类

    登录:

      用户 ID:全局唯一,不可变;

      用户手机号:全局唯一,很少变;

      Session ID:可重复生成,可丢失;

      密码:可丢失。

    发起会议:

      用户 ID:全局唯一,不可变;

      会议 ID:全局唯一,不可重复,每次算法生成;

      用户余额:全局强一致性一致性。

    加入会议:

      用户 ID:全局唯一,不可变;

      会议 ID:全局唯一,不可重复,每次算法生成。

  (3)数据同步

    登录:

      用户 ID:全局唯一,不可变,采用数据库同步 + 消息队列同步;

      用户手机号:全局唯一,很少变,采用数据库同步 + 消息队列同步;

      Session ID:可重复生成,可丢失,那么可以不同步,用户重新登录生成即可。

    发起会议:

      用户 ID:全局唯一,不可变 ,登录场景已经包含用户 ID 的同步设计;

      用户余额:全局一致性,采用数据库同步余额,充值只能在归属地充值;

      会议 ID:全局唯一,不可重复,每次新增 ,不同步,每次创建的时候用算法生成。

    加入会议:

      用户 ID:全局唯一,不可变 ,登录场景已经包含用户 ID 的同步设计;

      会议 ID:全局唯一,不可重复,每次新增,不同步,每次创建的时候用算法生成。

  (4)异常处理

    登录:

      新注册的用户数据还没有同步到异地机房 ,如何参加会议?第一种方式是直接不允许参加,用户体验不好;第二种方式是不登录也可以参加会议,由发起者生成邀请码/会议码/私密链接等方式邀请加入。

      用户密码没有同步到异地机房,登录不了怎么办?支持多种登录方式,例如手机验证码登录,绑定微信登录。

      新用户注册不了,此时有关键会议怎么办?不做处理,用其它方式加入会议。

    发起会议:

      用户在深圳机房开会的时候深圳机房挂了怎么办?用户重新发起会议即可。

      用户异地机房发起会议的时候余额不够,无法发起会议怎么办?业务上放松一部分约束,允许一定额度的欠费。

  3、视频会议异地多活架构示意图

    视频会议简化版异地多活架构如下图所示,其中用户服务器和会议服务器和上面王者荣耀的例子非常相似,就采用了相同的处理方案,不同的是用户的手机号可能发生变更,但是这个变更的概率很小,因此可以采用消息队列的方式进行数据同步即可。

        

 

 

 

posted @ 2022-05-26 02:09  李聪龙  阅读(1140)  评论(0编辑  收藏  举报