乐趣区

关于后端:高可用架构之异地多活

大家好,我是易安!

当谈到架构的高可用时,无论是高可用计算架构,还是高可用存储架构,其本质的设计目标都是为了解决局部服务器故障的场景下,如何保证系统可能持续提供服务。但在一些极其场景下,有可能所有服务器都呈现故障。例如,典型的有机房断电、机房火灾、地震、旱灾……这些极其状况会导致某个零碎所有服务器都故障,或者业务整体瘫痪,而且即便有其余地区的备份,把备份业务零碎全副复原到可能失常提供业务,破费的工夫也比拟长,可能是半小时,也可能是一天。因为备份零碎平时不对外提供服务,可能会存在很多暗藏的问题没有发现。如果业务冀望达到即便在此类灾难性故障的状况下,业务也不受影响,或者在几分钟内就可能很快复原,那么就须要设计异地多活架构。

明天我来聊聊异地多活架构,以及异地多活架构的设计技巧和流程。

利用场景

顾名思义,异地多活架构的关键点就是异地、多活,其中异地就是指地理位置上不同的中央,相似于“不要把鸡蛋都放在同一篮子里”;多活就是指不同地理位置上的零碎都可能提供业务服务,这里的“活”是流动、沉闷的意思。判断一个零碎是否合乎异地多活,须要满足两个规范:

  • 失常状况下,用户无论拜访哪一个地点的业务零碎,都可能失去正确的业务服务。
  • 某个中央业务异样的时候,用户拜访其余中央失常的业务零碎,可能失去正确的业务服务。

与“活”对应的是字是“备”,备是备份,失常状况下对外是不提供服务的,如果须要提供服务,则须要大量的人工干预和操作,破费大量的工夫能力让“备”变成“活”。

单纯从异地多活的形容来看,异地多活很弱小,可能保障在劫难的状况下业务都不受影响。那是不是意味着不论什么业务,咱们都要去实现异地多活架构呢?其实不然,因为实现异地多活架构不是没有代价的,相同其 代价很高 ,具体表现为:

  • 零碎复杂度会产生质的变动,须要设计简单的异地多活架构。
  • 老本会回升,毕竟要多在一个或者多个机房搭建独立的一套业务零碎。

因而,异地多活尽管性能很弱小,但也不是每个业务不管三七二十一都要上异地多活。例如,常见的新闻网站、企业外部的 IT 零碎、游戏、博客站点等,如果无奈接受异地多活带来的复杂度和老本,是能够不做异地多活的,只须要做异地备份即可。因为这类业务零碎即便中断,对用户的影响并不会很大,例如,A 新闻网站看不了,用户换个新闻网站即可。而共享单车、滴滴出行、支付宝、微信这类业务,就须要做异地多活了,这类业务零碎中断后,对用户的影响很大。例如,支付宝用不了,就没法买货色了;滴滴用不了,用户就打不到车了。

当然,如果业务规模很大,可能做异地多活的状况下还是尽量。首先,这样可能在异样的场景下给用户提供更好的体验;其次,业务规模很大必定会随同衍生的支出,例如广告支出,异地多活可能缩小异样场景带来的支出损失。同样以新闻网站为例,尽管从业务的角度来看,新闻类网站对用户影响不大,反正用户也能够从其余中央看到基本相同的新闻,甚至用户几个小时不看新闻也没什么问题。然而从网站自身来看,几个小时不可拜访必定会影响用户对网站的口碑;其次几个小时不可拜访,网站上的广告支出损失也会很大。

架构模式

依据地理位置上的间隔来划分,异地多活架构能够分为同城异区、跨城异地、跨国异地。接下来我具体解释一下每一种架构的细节与优缺点。

1. 同城异区

同城异区指的是将业务部署在同一个城市不同区的多个机房。例如,在北京部署两个机房,一个机房在海淀区,一个在通州区,而后将两个机房用专用的高速网络连接在一起。

如果咱们思考一些极其场景(例如,美加大停电、新奥尔良旱灾),同城异区仿佛没什么作用,那为何咱们还要设计同城异区这种架构呢?答案就在于“同城”。

同城的两个机房,间隔上个别大概就是几十千米,通过搭建高速的网络,同城异区的两个机房可能实现和同一个机房内简直一样的网络传输速度。这就意味着尽管是两个不同地理位置上的机房,但逻辑上咱们能够将它们看作同一个机房,这样的设计大大降低了复杂度,缩小了异地多活的设计和实现复杂度及老本。

那如果采纳了同城异区架构,一旦产生新奥尔良旱灾这种劫难怎么办呢?很遗憾,答案是无能为力。但咱们须要思考的是,这种极其劫难产生概率是比拟低的,可能几年或者十几年才产生一次。其次,除了这类劫难,机房火灾、机房停电、机房空调故障这类问题产生的概率更高,而且破坏力一样很大。而这些故障场景,同城异区架构都能够很好地解决。因而,联合复杂度、老本、故障产生概率来综合思考,同城异区是应答机房级别故障的最优架构。

2. 跨城异地

跨城异地指的是业务部署在不同城市的多个机房,而且间隔最好要远一些。例如,将业务部署在北京和广州两个机房,而不是将业务部署在广州和深圳的两个机房。

为何跨城异地要强调间隔要远呢?后面我在介绍同城异区的架构时提到同城异区不能解决新奥尔良旱灾这种问题,而两个城市离得太近又无奈应答如美加大停电这种问题,跨城异地其实就是为了解决这两类问题的,因而须要在间隔上比拟远,能力有效应对这类极其劫难事件。

跨城异地尽管可能有效应对极其劫难事件,但“间隔较远”这点并不只是一个间隔数字上的变动,而是质变引起了量变,导致了跨城异地的架构复杂度大大回升。间隔减少带来的最次要问题是两个机房的网络传输速度会升高,这不是以人的意志为转移的,而是物理定律决定的,即光速真空流传大概是每秒 30 万千米,在光纤中传输的速度大概是每秒 20 万千米,再加上传输中的各种网络设备的解决,理论还远远达不到实践上的速度。

除了间隔上的限度,两头传输各种不可控的因素也十分多。例如,挖掘机把光纤挖断、中美海底电缆被拖船扯断、骨干网故障等,这些线路很多是第三方保护,针对故障咱们基本无能为力也无奈预知。例如,广州机房到北京机房,失常状况下 RTT 大概是 50 毫秒左右,遇到网络稳定之类的状况,RTT 可能飙升到 500 毫秒甚至 1 秒,更不用说常常产生的线路丢包问题,那提早可能就是几秒几十秒了。

以上形容的问题,尽管同城异区实践上也会遇到,但因为同城异区间隔较短,两头通过的线路和设施较少,问题产生的概率会低很多。而且同城异区间隔短,即便是搭建多条互联通道,老本也不会太高,而跨城异区间隔太远,搭建或者应用多通道的老本会高不少。

跨城异地间隔较远带来的网络传输提早问题,给异地多活架构设计带来了复杂性,如果要做到真正意义上的多活,业务零碎须要思考部署在不同地点的两个机房,在数据短时间不统一的状况下,还可能失常提供业务。这就引入了一个看似矛盾的中央:数据不统一业务必定不会失常,但跨城异地必定会导致数据不统一。

如何解决这个问题呢?重点还是在“数据”上,即依据数据的个性来做不同的架构。如果是强一致性要求的数据,例如银行存款余额、支付宝余额等,这类数据实际上是无奈做到跨城异地多活的。咱们来看一个假如的例子,如果咱们做一个互联网金融的业务,用户余额反对跨城异地多活,咱们的零碎别离部署在广州和北京,那么如果挖掘机挖断光缆后,会呈现如下场景:

  • 用户 A 余额有 10000 元钱,北京和广州机房都是这个数据。
  • 用户 A 向用户 B 转了 5000 元钱,这个操作是在广州机房实现的,实现后用户 A 在广州机房的余额是 5000 元。
  • 因为广州和北京机房网络被挖掘机挖断,广州机房无奈将余额变动告诉北京机房,此时北京机房用户 A 的余额还是 10000 元。
  • 用户 A 到北京机房又发动转账,此时他看到本人的余额还有 10000 元,于是向用户 C 转账 10000 元,转账实现后用户 A 的余额变为 0。
  • 用户 A 到广州机房一看,余额怎么还有 5000 元?于是连忙又发动转账,转账 5000 元给用户 D;此时广州机房用户 A 的余额也变为 0 了。

最终,原本余额 10000 元的用户 A,却转了 20000 元进来给其余用户。

对于以上这种假如场景,尽管普通用户很难这样自若地操作,但如果真的这么做,被黑客发现后,结果不堪设想。正因为如此,支付宝等金融相干的零碎,对余额这类数据,个别不会做跨城异地的多活架构,而只能采纳同城异区这种架构。

而对数据一致性要求不那么高,或者数据不怎么扭转,或者即便数据失落影响也不大的业务,跨城异地多活就可能派上用场了。例如,用户登录(数据不统一时用户从新登录即可)、新闻类网站(一天内的新闻数据变动较少)、微博类网站(失落用户公布的微博或者评论影响不大),这些业务采纳跨城异地多活,可能很好地应答极其劫难的场景。

3. 跨国异地

跨国异地指的是业务部署在不同国家的多个机房。相比跨城异地,跨国异地的间隔就更远了,因而数据同步的延时会更长,失常状况下可能就有几秒钟了。这种水平的提早曾经无奈满足异地多活规范的第一条:“失常状况下,用户无论拜访哪一个地点的业务零碎,都可能失去正确的业务服务”。例如,假如有一个微博类网站,别离在中国的上海和美国的纽约都建了机房,用户 A 在上海机房发表了一篇微博,此时如果他的一个关注者 B 用户拜访到美国的机房,很可能无奈看到用户 A 刚刚发表的微博。尽管跨城异地也会有此类同步延时问题,但失常状况下几十毫秒的延时对用户来说根本无感知的;而延时达到几秒钟就感觉比拟显著了。

因而,跨国异地的“多活”,和跨城异地的“多活”,理论的含意并不完全一致。跨国异地多活的次要利用场景个别有这几种状况:

  • 为不同地区用户提供服务

例如,亚马逊中国是为中国用户服务的,而亚马逊美国是为美国用户服务的,亚马逊中国的用户如果拜访美国亚马逊,是无奈用亚马逊中国的账号登录美国亚马逊的。

  • 只读类业务做多活

例如,谷歌的搜寻业务,因为用户搜寻材料时,这些材料都曾经存在于谷歌的搜索引擎下面,无论是拜访英国谷歌,还是拜访美国谷歌,搜寻后果基本相同,并且对用户来说,也不须要搜寻到最新的实时材料,跨国异地的几秒钟网络提早,对搜寻后果是没有什么影响的。、

接下来我将介绍跨城异地多活架构设计的一些技巧和步骤

技巧 1:保障外围业务的异地多活

“异地多活”是为了保障业务的高可用,但很多架构师在思考这个“业务”时,会不盲目地陷入一个思维误区:我要保障所有业务都能“异地多活”!

假如咱们须要做一个“用户子系统”,这个子系统负责“注册”“登录”“用户信息”三个业务。为了反对海量用户,咱们设计了一个“用户分区”的架构,即失常状况下用户属于某个主分区,每个分区都有其余数据的备份,用户用邮箱或者手机号注册,路由层拿到邮箱或者手机号后,通过 Hash 计算属于哪个核心,而后申请对应的业务核心。根本的架构如下:

这样一个零碎,如果 3 个业务要同时实现异地多活,会发现这些难以解决的问题:

  • 注册问题

A 核心注册了用户,数据还未同步到 B 核心,此时 A 核心宕机,为了反对注册业务多活,能够筛选 B 核心让用户去从新注册。看起来很容易就反对多活了,但认真思考一下会发现这样做会有问题:一个手机号只能注册一个账号,A 核心的数据没有同步过去,B 核心无奈判断这个手机号是否反复,如果 B 核心让用户注册,起初 A 核心复原了,发现数据有抵触,怎么解决?实际上是无奈解决的,因为同一个手机号注册的账号不能当前一次注册为准;而如果 B 核心不反对原本属于 A 核心的业务进行注册,注册业务的多活又成了空谈。

如果咱们批改业务规定,容许一个手机号注册多个账号不就能够了吗?

这样做是不可行的,相似一个手机号只能注册一个账号这种规定,是外围业务规定,批改外围业务规定的代价十分大,简直所有的业务都要从新设计,为了架构设计去扭转业务规定(而且是这么外围的业务规定)是得失相当的。

  • 用户信息问题

用户信息的批改和注册有相似的问题,即 A、B 两个核心在异样的状况下都批改了用户信息,如何解决抵触?

因为用户信息并没有账号那么要害,一种简略的解决形式是依照工夫合并,即最初批改的失效。业务逻辑上没问题,但实际操作也有一个很要害的“坑”:怎么保障多个核心所有机器工夫相对统一?在异地多核心的网络下,这个是无奈保障的,即便有工夫同步也无奈齐全保障,只有两个核心的时间误差超过 1 秒,数据就可能呈现凌乱,即先批改的反而失效。

还有一种形式是生成全局惟一递增 ID,这个计划的老本很高,因为这个全局惟一递增 ID 的零碎自身又要思考异地多活,同样波及数据一致性和抵触的问题。

综合下面的简略剖析能够发现,如果“注册”“登录”“用户信息”全副都要反对异地多活,实际上是挺难的,有的问题甚至是无解的。那这种状况下咱们应该如何思考“异地多活”的架构设计呢?答案其实很简略: 优先实现外围业务的异地多活架构!

对于这个模仿案例来说,“登录”才是最外围的业务,“注册”和“用户信息”尽管也是次要业务,但并不一定要实现异地多活,次要起因在于业务影响不同。对于一个日活 1000 万的业务来说,每天注册用户可能是几万,批改用户信息的可能还不到 1 万,但登录用户是 1000 万,很显著咱们应该保障登录的异地多活。

对于新用户来说,注册不了的影响并不显著,因为他还没有真正开始应用业务。用户信息批改也相似,临时批改不了用户信息,对于其业务不会有很大影响。而如果有几百万用户登录不了,就相当于几百万用户无奈应用业务,对业务的影响就十分大了:公司的客服热线很快就被打爆,微博、微信上到处都在传业务宕机,论坛外面到处是埋怨的用户,那就是互联网大事件了!

而登录实现“异地多活”恰好是最简略的,因为每个核心都有所有用户的账号和明码信息,用户在哪个核心都能够登录。用户在 A 核心登录,A 核心宕机后,用户到 B 核心从新登录即可。

如果某个用户在 A 核心批改了明码,此时数据还没有同步到 B 核心,用户到 B 核心登录是无奈登录的,这个怎么解决?这个问题其实就波及另外一个设计技巧了,我卖个关子稍后再谈。

技巧 2:保障外围数据最终一致性

异地多活实质上是通过异地的数据冗余,来保障在极其异样的状况下业务也可能失常提供给用户,因而数据同步是异地多活架构设计的外围。但大部分架构师在思考数据同步计划时,会人不知; 鬼不觉地陷入完美主义误区:我要所有数据都实时同步!

数据冗余是要将数据从 A 地同步到 B 地,从业务的角度来看是越快越好,最好和本地机房一样的速度最好。但让人头疼的问题正在这里:异地多活实践上就不可能很快,因为这是物理定律决定的。

因而异地多活架构面临一个无奈彻底解决的矛盾:业务上要求数据疾速同步,物理上正好做不到数据疾速同步,因而所有数据都实时同步,实际上是一个无奈达到的指标。

既然是无奈彻底解决的矛盾,那就只能想方法尽量减少影响。有几种办法能够参考:

  • 尽量减少异地多活机房的间隔,搭建高速网络

搭建跨城异地的高速网络老本远远超过同城异区的高速网络,老本微小,个别只有巨头公司能力承当。

  • 尽量减少数据同步,只同步外围业务相干的数据

简略来说就是不重要的数据不同步,同步后没用的数据不同步,只同步外围业务相干的数据。

以后面的“用户子系统”为例,用户登录所产生的 token 或者 session 信息,数据量很大,但其实并不需要同步到其余业务核心,因为这些数据失落后从新登录就能够再次获取了。

这时你可能会想到:这些数据失落后要求用户从新登录,影响用户体验!

的确如此,毕竟须要用户从新输出账户和明码信息,或者至多要弹出登录界面让用户点击一次,但相比为了同步所有数据带来的代价,这个影响齐全能够承受。

  • 保障最终一致性,不保障实时一致性

最终一致性就是业务不依赖数据同步的实时性,只有数据最终能统一即可。例如,A 机房注册了一个用户,业务上不要求可能在 50 毫秒内就同步到所有机房,失常状况下要求 5 分钟同步到所有机房即可,异常情况下甚至能够容许 1 小时或者 1 天后可能统一。

最终一致性在具体实现时,还须要依据不同的数据特色,进行差异化的解决,以满足业务须要。例如,对“账号”信息来说,如果在 A 机房新注册的用户 5 分钟内正好跑到 B 机房了,此时 B 机房还没有这个用户的信息,为了保障业务的正确,B 机房就须要依据路由规定到 A 机房申请数据。

而对“用户信息”来说,5 分钟后同步也没有问题,也不须要采取其余措施来补救,但还是会影响用户体验,即用户看到了旧的用户信息,这个问题怎么解决呢?如同又是一个解决不了的问题,和后面我留下的两个问题一起,在最初我来给出答案。

技巧 3:采纳多种手段同步数据

数据同步是异地多活架构设计的外围,侥幸的是基本上存储系统自身都会有同步的性能。例如,MySQL 的主备复制、Redis 的 Cluster 性能、Elasticsearch 的集群性能。这些零碎自身的同步性能曾经比拟弱小,可能间接拿来就用,但这也无形中将咱们引入了一个思维误区:只应用存储系统的同步性能!

既然说存储系统自身就有同步性能,而且同步性能还很弱小,为何说只应用存储系统是一个思维误区呢?因为尽管绝大部分场景下,存储系统自身的同步性能基本上也够用了,但在某些比拟极其的状况下,存储系统自身的同步性能可能难以满足业务需要。

以 MySQL 为例,MySQL 5.1 版本的复制是单线程的复制,在网络抖动或者大量数据同步时,常常产生提早较长的问题,短则提早十几秒,长则可能达到十几分钟。而且即便咱们通过监控的伎俩晓得了 MySQL 同步时延较长,也难以采取什么措施,只能干等。

Redis 又是另外一个问题,Redis 3.0 之前没有 Cluster 性能,只有主从复制性能,而为了设计上的简略,Redis 2.8 之前的版本,主从复制有一个比拟大的隐患:从机宕机或者和主机断开连接都须要从新连贯主机,从新连贯主机都会触发全量的主从复制。这时主机会生成内存快照,主机仍然能够对外提供服务,然而作为读的从机,就无奈提供对外服务了,如果数据量大,复原的工夫会相当长。

综合下面的案例能够看出,存储系统自身自带的同步性能,在某些场景下是无奈满足业务须要的。尤其是异地多机房这种部署,各种各样的异常情况都可能呈现,当咱们只思考存储系统自身的同步性能时,就会发现无奈做到真正的异地多活。

解决的计划就是拓开思路,防止只应用存储系统的同步性能,能够将多种手段配合存储系统的同步来应用,甚至能够不采纳存储系统的同步计划,改用本人的同步计划。

还是以后面的“用户子系统”为例,咱们能够采纳如下几种形式同步数据:

  • 音讯队列形式

对于账号数据,因为账号只会创立,不会批改和删除(假如咱们不提供删除性能),咱们能够将账号数据通过音讯队列同步到其余业务核心。

  • 二次读取形式

某些状况下可能呈现音讯队列同步也提早了,用户在 A 核心注册,而后拜访 B 核心的业务,此时 B 核心本地拿不到用户的账号数据。为了解决这个问题,B 核心在读取本地数据失败时,能够依据路由规定,再去 A 核心拜访一次(这就是所谓的二次读取,第一次读取本地,本地失败后第二次读取对端),这样就可能解决异常情况下同步提早的问题。

  • 存储系统同步形式

对于明码数据,因为用户改明码频率较低,而且用户不可能在 1 秒内间断改屡次明码,所以通过数据库的同步机制将数据复制到其余业务核心即可,用户信息数据和明码相似。

  • 回源读取形式

对于登录的 session 数据,因为数据量很大,咱们能够不同步数据;但当用户在 A 核心登录后,而后又在 B 核心登录,B 核心拿到用户上传的 session id 后,依据路由判断 session 属于 A 核心,间接去 A 核心申请 session 数据即可;反之亦然,A 核心也能够到 B 核心去获取 session 数据。

  • 从新生成数据形式

对于“回源读取”场景,如果异常情况下,A 核心宕机了,B 核心申请 session 数据失败,此时就只能登录失败,让用户从新在 B 核心登录,生成新的 session 数据。

留神:以上计划仅仅是示意,理论的设计方案要比这个简单一些,还有很多细节要思考。

综合上述的各种措施,最初“用户子系统”同步形式整体如下:

技巧 4:只保障绝大部分用户的异地多活

某些场景下咱们无奈保障 100% 的业务可用性,总是会有肯定的损失。例如,明码不同步导致无奈登录、用户信息不同步导致用户看到旧的信息等,这个问题怎么解决呢?

其实这个问题波及异地多活架构设计中一个典型的思维误区:我要保障业务 100% 可用!但极其状况下就是会丢一部分数据,就是会有一部分数据不能同步,有没有什么奇妙能做到 100% 可用呢?

很遗憾,答案是没有!异地多活也无奈保障 100% 的业务可用,这是由物理法则决定的,光速和网络的传播速度、硬盘的读写速度、极其异常情况的不可控等,都是无奈 100% 解决的。所以针对这个思维误区,我的答案是“忍”!也就是说咱们要忍耐这一小部分用户或者业务上的损失,否则原本想为了保障最初的 0.01% 的用户的可用性,做一个完满计划,后果却发现 99.99% 的用户都保障不了了。

对于某些实时强一致性的业务,实际上受影响的用户会更多,甚至可能达到 1 / 3 的用户。以银行转账这个业务为例,假如小明在北京 XX 银行开了账号,如果小明要转账,肯定要北京的银行业务核心才可用,否则就不容许小明本人转账。如果不这样的话,假如在北京和上海两个业务核心实现了实时转账的异地多活,某些异常情况下就可能呈现小明只有 1 万元贷款,他在北京转给了张三 1 万元,而后又到上海转给了李四 1 万元,两次转账都胜利了。这种破绽如果被人利用,结果不堪设想。

当然,针对银行转账这个业务,尽管无奈做到“实时转账”的异地多活,但能够通过非凡的业务伎俩让转账业务也能实现异地多活。例如,转账业务除了“实时转账”外,还提供“转账申请”业务,即小明在上海业务核心提交转账申请,但上海的业务核心并不立刻转账,而是记录这个转账申请,而后后盾异步发动真正的转账操作,如果此时北京业务核心不可用,转账申请就能够持续期待重试;假如期待 2 个小时后北京业务核心复原了,此时上海业务核心去申请转账,发现余额不够,这个转账申请就失败了。小明再登录上来就会看到转账申请失败,起因是“余额有余”。

不过须要留神的是“转账申请”的这种形式尽管有助于实现异地多活,但其实还是就义了用户体验的,对于小明来说,原本一次操作的事件,须要分为两次:一次提交转账申请,另外一次是要确认是否转账胜利。

尽管咱们无奈做到 100% 可用性,但并不意味着咱们什么都不能做,为了让用户心里更好受一些,咱们能够采取一些措施进行安抚或者弥补,例如:

  • 挂布告

阐明当初有问题和根本的问题起因,如果不明确起因或者不不便说出起因,能够公布“技术哥哥正在紧急解决”这类比拟轻松和乏味的布告。

  • 预先对用户进行弥补

例如,送一些业务上可用的代金券、小礼包等,缩小用户的埋怨。

  • 补充体验

对于为了做异地多活而带来的体验损失,能够想一些办法缩小或者躲避。以“转账申请”为例,为了让用户不必确认转账申请是否胜利,咱们能够在转账胜利或者失败后间接给用户发个短信,通知他转账后果,这样用户就不必时不时地登录零碎来确认转账是否胜利了。

设计跨城异地多活架构

咱们讲完了异地多活设计的外围要点,上面咱们谈一下如何设计跨城异地多活架构。

第 1 步:业务分级

依照肯定的规范将业务进行分级,挑选出外围的业务,只为外围业务设计异地多活,升高计划整体复杂度和实现老本。

常见的分级规范有上面几种:

  • 访问量大的业务

以用户管理系统为例,业务包含登录、注册、用户信息管理,其中登录的访问量必定是最大的。

  • 外围业务

以 QQ 为例,QQ 的主场景是聊天,QQ 空间尽管也是重要业务,但和聊天相比,重要性就会低一些,如果要从聊天和 QQ 空间两个业务外面筛选一个做异地多活,那显著聊天要更重要(当然,此类公司如腾讯,应该是两个都实现了异地多活的)。

  • 产生大量支出的业务

同样以 QQ 为例,聊天可能很难为腾讯带来收益,因为聊天没法插入广告;而 QQ 空间反而可能带来更多收益,因为 QQ 空间能够插入很多广告,因而如果从支出的角度来看,QQ 空间做异地多活的优先级反而高于 QQ 聊天了。

以咱们始终在举例的用户管理系统为例,“登录”业务合乎“访问量大的业务”和“外围业务”这两条规范,因而咱们将登录业务作为外围业务。

第 2 步:数据分类

挑选出外围业务后,须要对外围业务相干的数据进一步剖析,目标在于辨认所有的数据及数据特色,这些数据特色会影响前面的方案设计。

常见的数据特征分析维度有:

  • 数据量

这里的数据量包含总的数据量和新增、批改、删除的量。对异地多活架构来说,新增、批改、删除的数据就是可能要同步的数据,数据量越大,同步提早的几率越高,同步计划须要思考相应的解决方案。

  • 唯一性

唯一性指数据是否要求多个异地机房产生的同类数据必须保障惟一。例如用户 ID,如果两个机房的两个不同用户注册后生成了一样的用户 ID,这样业务上就出错了。

数据的唯一性影响业务的多活设计,如果数据不须要惟一,那就阐明两个中央都产生同类数据是可能的;如果数据要求必须惟一,要么只能一个中心点产生数据,要么须要设计一个数据惟一生成的算法。

  • 实时性

实时性指如果在 A 机房批改了数据,要求多长时间必须同步到 B 机房,实时性要求越高,对同步的要求越高,计划越简单。

  • 可失落性

可失落性指数据是否能够失落。例如,写入 A 机房的数据还没有同步到 B 机房,此时 A 机房机器宕机会导致数据失落,那这部分失落的数据是否对业务会产生重大影响。

例如,登录过程中产生的 session 数据就是可失落的,因为用户只有从新登录就能够生成新的 session;而用户 ID 数据是不可失落的,失落后用户就会失去所有和用户 ID 相干的数据,例如用户的好友、用户的钱等。

  • 可恢复性

可恢复性指数据失落后,是否能够通过某种伎俩进行复原,如果数据能够复原,至多阐明对业务的影响不会那么大,这样能够相应地升高异地多活架构设计的复杂度。

例如,用户的微博失落后,用户从新发一篇截然不同的微博,这个就是可复原的;或者用户明码失落,用户能够通过找回明码来从新设置一个新密码,这也算是能够复原的;而用户账号如果失落,用户无奈登录零碎,零碎也无奈通过其余路径来复原这个账号,这就是不可复原的数据。

咱们同样以用户管理系统的登录业务为例,简略剖析如下表所示。

第 3 步:数据同步

确定数据的特点后,咱们能够依据不同的数据设计不同的同步计划。常见的数据同步计划有:

  • 存储系统同步

这是最罕用也是最简略的同步形式。例如,应用 MySQL 的数据主从数据同步、主主数据同步。

这类数据同步的长处是应用简略,因为简直支流的存储系统都会有本人的同步计划;毛病是这类同步计划都是通用的,无奈针对业务数据特点做定制化的管制。例如,无论须要同步的数据量有多大,MySQL 都只有一个同步通道。因为要保障事务性,一旦数据量比拟大,或者网络有提早,则同步提早就会比较严重。

  • 音讯队列同步

采纳独立音讯队列进行数据同步,常见的音讯队列有 Kafka、RocketMQ 等。

音讯队列同步适宜无事务性或者无时序性要求的数据。例如,用户账号,两个用户先后注册了账号 A 和 B,如果同步时先把 B 同步到异地机房,再同步 A 到异地机房,业务上是没有问题的。而如果是用户明码,用户先改了明码为 m,而后改了明码为 n,同步时必须先保障同步 m 到异地机房,再同步 n 到异地机房;如果反过来,同步后用户的明码就不对了。因而,对于新注册的用户账号,咱们能够采纳音讯队列同步了;而对于用户明码,就不能采纳音讯队列同步了。

  • 反复生成

数据不同步到异地机房,每个机房都能够生成数据,这个计划适宜于能够反复生成的数据。例如,登录产生的 cookie、session 数据、缓存数据等。

咱们同样以用户管理系统的登录业务为例,针对不同的数据特点设计不同的同步计划,如下表所示。

第 4 步:异样解决

无论数据同步计划如何设计,一旦呈现极其异样的状况,总是会有局部数据出现异常的。例如,同步提早、数据失落、数据不统一等。异样解决就是假如在呈现这些问题时,零碎将采取什么措施来应答。异样解决次要有以下几个目标:

  • 问题产生时,防止大量数据异样导致整体业务不可用。
  • 问题复原后,将异样的数据进行修改。
  • 对用户进行安抚,补救用户损失。

常见的异样解决措施有这几类:

1. 多通道同步

多通道同步的含意是采取多种形式来进行数据同步,其中某条通道故障的状况下,零碎能够通过其余形式来进行同步,这种形式能够应答同步通道处故障的状况。

以用户管理系统中的用户账号数据为例,咱们的设计方案一开始筛选了音讯队列的形式进行同步,思考异常情况下,音讯队列同步通道可能中断,也可能提早很重大;为了保障新注册账号可能疾速同步到异地机房,咱们再减少一种 MySQL 同步这种形式作为备份。这样针对用户账号数据同步,零碎就有两种同步形式:MySQL 主从同步和音讯队列同步。除非两个通道同时故障,否则用户账号数据在其中一个通道异样的状况下,可能通过另外一个通道持续同步到异地机房,如下图所示。

多通道同步设计的计划关键点有:

  • 个别状况下,采取两通道即可,采取更多通道实践上可能升高危险,但付出的老本也会减少很多。
  • 数据库同步通道和音讯队列同步通道不能采纳雷同的网络连接,否则一旦网络故障,两个通道都同时故障;能够一个走公网连贯,一个走内网连贯。
  • 须要数据是能够反复笼罩的,即无论哪个通道先到哪个通道后到,最终后果是一样的。例如,新建账号数据就合乎这个规范,而明码数据则不合乎这个规范。

2. 同步和拜访联合

这里的拜访指异地机房通过零碎的接口来进行数据拜访。例如业务部署在异地两个机房 A 和 B,B 机房的业务零碎通过接口来拜访 A 机房的零碎获取账号信息,如下图所示。

同步和拜访联合计划的设计关键点有:

  • 接口拜访通道和数据库同步通道不能采纳雷同的网络连接,不能让数据库同步和接口拜访都走同一条网络通道,能够采纳接口拜访走公网连贯,数据库同步走内网连贯这种形式。
  • 数据有路由规定,能够依据数据来推断应该拜访哪个机房的接口来读取数据。例如,有 3 个机房 A、B、C,B 机房拿到一个不属于 B 机房的数据后,须要依据路由规定判断是拜访 A 机房接口,还是拜访 C 机房接口。
  • 因为有同步通道,优先读取本地数据,本地数据无奈读取到再通过接口去拜访,这样能够大大降低跨机房的异地接口拜访数量,适宜于实时性要求十分高的数据。

3. 日志记录

日志记录次要用于用户故障复原后对数据进行复原,其次要形式是每个要害操作前后都记录相干一条日志,而后将日志保留在一个独立的中央,当故障复原后,拿出日志跟数据进行比照,对数据进行修复。

为了应答不同级别的故障,日志保留的要求也不一样,常见的日志保留形式有:

  • 服务器上保留日志,数据库中保留数据,这种形式能够应答单台数据库服务器故障或者宕机的状况。
  • 本地独立零碎保留日志,这种形式能够应答某业务服务器和数据库同时宕机的状况。例如,服务器和数据库部署在同一个机架,或者同一个电源线路上,就会呈现服务器和数据库同时宕机的状况。
  • 日志异地保留,这种形式能够应答机房宕机的状况。

下面不同的日志保留形式,应答的故障越重大,计划自身的复杂度和老本就会越高,理论抉择时须要综合思考老本和收益状况。

4. 用户弥补

无论采纳什么样的异样解决措施,都只能最大限度地升高受到影响的范畴和水平,无奈齐全做到没有任何影响。例如,双同步通道有可能同时呈现故障、日志记录计划自身日志也可能失落。因而,无论如许完满的计划,故障的场景下总是可能有一小部分用户业务上出问题,零碎无法弥补这部分用户的损失。但咱们能够采纳人工的形式对用户进行弥补,补救用户损失,造就用户的忠诚度。简略来说,零碎的计划是为了保障 99.99% 的用户在故障的场景下业务不受影响,人工的弥补是为了补救 0.01% 的用户的损失。

总结

明天咱们谈了异地多活架构的利用场景和常见架构模式,联合 CAP、BASE 等实践讲了异地多活的设计技巧,并具体讲述了如何设计异地多活架构,心愿对你有所帮忙。

本文由 mdnice 多平台公布

退出移动版