高可用容灾架构演进之路
概述
随着移动互联网的深入发展,用户增长达到一定规模后,不少企业都会面高并发业务和临海量数据的挑战,传统的单机房在机器容量上存在瓶颈。在一些极端场景下,有可能所有服务器都出现故障,例如机房断电、机房火灾、地震等这些不可抗拒因素会导致系统所有服务器都故障从而导致业务整体瘫痪,而且即使有其他地区的备份,把备份业务系统全部恢复到能够正常提供业务,花费的时间也比较长。为了满足中心业务连续性,增强抗风险能力,多活作为一种可靠的高可用部署架构,成为各大互联网公司的首要选择。
对于系统高可用来说,相信大家都知道如下新闻:
2015 年 5 月 27 日,杭州市某地光纤被挖断,近 3 亿用户长达 5 小时无法访问支付宝
2021 年 7 月 13 日,B 站部分服务器机房发生故障,造成整站持续 3 个小时无法访问
2021 年 10 月 9 日,富途证券服务器机房发生电力闪断故障,造成用户 2 个小时无法登陆、交易
而高可用这个概念,通常用 2 个指标来衡量:
平均故障间隔 MTBF(Mean Time Between Failure):表示两次故障的间隔时间,也就是系统「正常运行」的平均时间,这个时间越长,说明系统稳定性越高
故障恢复时间 MTTR(Mean Time To Repair):表示系统发生故障后「恢复的时间」,这个值越小,故障对用户的影响越小
可用性与这两者的关系:
可用性(Availability)= MTBF / (MTBF + MTTR) * 100%
这个公式得出的结果是一个「比例」,通常我们会用「N 个 9」来描述一个系统的可用性。
从这张图你可以看到,要想达到 4 个 9 以上的可用性,平均每天故障时间必须控制在 10 秒以内。
也就是说,只有故障的时间「越短」,整个系统的可用性才会越高,每提升 1 个 9,都会对系统提出更高的要求。
如何从故障中快速恢复系统访问,是对技术架构来说是一个很大的挑战,接下来将和大家介绍高可用架构容灾演进之路。
高可用架构演进
目前主要的容灾类型可以分为以下三类:
同城(跨可用区),主要分为同城灾备、同城双活以及同城多活。
异地(跨地域),主要分为异地双读、异地应用双活以及异地双活。
其他类型,包括两地三中心、两地三活以及单元化。
没有一套容灾方案可以适用于所有场景,我们需要结合实际业务发展趋势、业务系统的特征以及能够投入多少资源成本等方面综合评估,最终选出最适合的容灾架构方案。
同城灾备
同城灾备实际上是一种冷备,同一个城市至少部署两个机房A、B,B备机房平时不提供服务能力,主要作为A主机房的备份,主备之间数据采用单向同步的形式,这两个机房的网络用一条「专线」连通。
A 机房整个挂掉,我们只需要做 2 件事即可:
B 机房所有从库提升为主库
DNS 指向 B 机房接入层,接入流量,业务恢复
这样一来,恢复速度快了很多,提高了整个系统的高可用。
到这里你会发现,B 机房从最开始的「空空如也」,演变到现在,几乎是「镜像」了一份 A 机房的所有东西,从最上层的接入层,到中间的业务应用,到最下层的存储。两个机房唯一的区别是,A 机房的存储都是主库,而 B 机房都是从库。
这种冷备方案的优劣势如下:
优势:
部署简单,将同一套架构完全复制到另外机房即可,数据做单向同步,对业务的改造极少。
劣势:
为备数据中心存在资源浪费的情况;关键时刻不敢切流,容易出现版本、参数、操作系统不一致等情况;
另外灾备中心平时不会启用,同城灾备会造成一些物理资源的浪费。
从整个高可用角度来说,同城灾备是最初级的容灾设计方案,数据不完整、恢复数据期间业务不可用,整个系统的可用性还是无法得到保证,DNS解析切换至少需要10分钟以上,整个故障恢复来说也需要一些时间。
同城双活
同城双活是在同城或相近区域内建立两个机房。同城双机房距离比较近,通信线路质量较好,比较容易实现数据的同步复制 ,保证高度的数据完整性和数据零丢失。同城两个机房各承担一部分流量,一般入口流量完全随机,内部RPC调用尽量通过就近路由闭环在同机房,相当于两个机房镜像部署了两个独立集群,数据仍然是单点写到主机房数据库,然后实时同步到另外一个机房。
因为 A 机房的存储都是主库,所以我们把 A 机房叫做「主机房」,B 机房叫「从机房」,部署架构如下图:
业务应用在操作数据库时,需要区分「读写分离」(一般用中间件实现),即两个机房的「读」流量,可以读任意机房的存储,但「写」流量,只允许写 A 机房,因为主库在 A 机房。
这种方案的优劣势如下:
优势:
服务同城双活,数据同城灾备,同城不丢失数据情况下跨机房级别容灾。
架构方案较为简单,核心是解决底层数据双活,由于双机房距离近,通信质量好,底层储存例如mysql可以采用同步复制,有效保证双机房数据一致性。
劣势:
数据库写数据存在跨机房调用,在复杂业务以及链路下频繁跨机房调用增加响应时间,影响系统性能和用户体验。
保证同城市地区容灾,当服务所在的城市或者地区网络整体故障、发生不可抗拒的地震、水灾等自然灾害时候有服务故障以及丢失数据风险。
服务规模足够大(例如单体应用超过万台机器),所有机器链接一个主数据库实例会引起连接不足问题。
项目中用到了 MySQL、Redis、MongoDB 等等,操作这些数据库,都需要区分读写请求,所以这块需要一定的业务「改造」成本。
业务改造完成后,B 机房可以慢慢接入流量,从 10%、30%、50% 逐渐覆盖到 100%,你可以持续观察 B 机房的业务是否存在问题,有问题及时修复,逐渐让 B 机房的工作能力,达到和 A 机房相同水平。
现在,因为 B 机房实时接入了流量,此时如果 A 机房挂了,那我们就可以「大胆」地把 A 的流量,全部切换到 B 机房,完成快速切换!
到这里你可以看到,我们部署的 B 机房,在物理上虽然与 A 有一定距离,但整个系统从「逻辑」上来看,我们是把这两个机房看做一个「整体」来规划的,也就是说,相当于把 2 个机房当作 1 个机房来用。
其实真正意义上的同城多活是指应用层多活和数据层同时多活,只有这2层多活,才能达到实际的流量切换与连续业务,当然在实施过程中从开发效率及商业目标等考虑,会使用一些伪同城多活的方案,如早期阿里为了应对双11购物,杭州机房与上海机房采用的就是伪同城多活,应用层多活,2个应用节点同时写一个机房数据,并且很好的解决双11大流量购物需求。同城多活里,同城应用可以跨机房写数据库,应用层面的多活就实现了。而在强化了应用层面的容错和故障处置手段之后,因为同城的数据传输延迟小,在主数据库故障时,应用可快速把主数据库切换到其他机房的从数据库。在这种机制下,不单可以实现数据库的多活,而且进一步实现了数据中心层面的同城多活,理论上任何一个数据中心中断都不会导致业务中断,切换过程也非常简单。
两地三中心
基于上面同城双活方案,有一个问题是无法解决的,无法抵抗地震、水灾这种级别问题,引来了可以考虑增加一个异地冗余冷备,通常建议冗余冷备机房同中心机房的距离要在 1000 公里以上,这样才能应对城市级别的灾难,也就是本章节要介绍的两地三中心方案。
假设之前的 A、B 机房在北京,那这次新部署的 C 机房可以放在上海。
两地是指 2 个城市,三中心是指有 3 个机房,其中 2 个机房在同一个城市,并且同时提供服务,第 3 个机房部署在异地,只做数据灾备。
这种架构方案,通常用在银行、金融、政企相关的项目中,例如工行号称也是支持两地三中心,支付宝目前实施的两地五中心多活方案。它的问题还是前面所说的,启用灾备机房需要时间,而且启用后的服务,不确定能否如期工作。
这种方案的优劣势:
优势:
服务同城双活,数据同城灾备,同城不丢失数据情况下跨机房级别容灾。
架构方案较为简单,核心是解决底层数据双活,由于双机房距离近,通信质量好,底层储存例如mysql可以采用同步复制,有效保证双机房数据一致性。
灾备中心能防范同城双中心同时出现故障时候利用备份数据进行业务的恢复。
劣势:
数据库写数据存在跨机房调用,在复杂业务以及链路下频繁跨机房调用增加响应时间,影响系统性能和用户体验。
服务规模足够大(例如单体应用超过万台机器),所有机器链接一个主数据库实例会引起连接不足问题。
出问题不敢轻易将流量切往异地数据备份中心,异地的备份数据中心是冷的,平时没有流量进入,因此出问题需要较长时间对异地灾备机房进行验证。
浪费硬件资源,冷备份中心正常情况下始终全量备份,不对外提供业务,很可能是长期一直不使用的情况。
异地双活
上面的两地三中心的方案,本质上还是同城双活,异地数据备份,不能解决同城出现自然灾害导致的高可用问题。
我们不再把 A、B 机房部署在同一个城市,而是分开部署,例如 A 机房放在北京,B 机房放在上海。
具体部署架构如下:
此时两个机房都接入流量,那上海机房的请求,可能要去读写北京机房的存储,这里存在一个很大的问题:网络延迟。
因为两个机房距离较远,受到物理距离的限制,现在,两地之间的网络延迟就变成了「不可忽视」的因素了。
北京到上海的距离大约 1300 公里,即使架设一条高速的「网络专线」,光纤以光速传输,一个来回也需要近 10ms 的延迟。
况且,网络线路之间还会经历各种路由器、交换机等网络设备,实际延迟可能会达到 30ms ~ 100ms,如果网络发生抖动,延迟甚至会达到 1 秒。
不止是延迟,远距离的网络专线质量,是远远达不到机房内网络质量的,专线网络经常会发生延迟、丢包、甚至中断的情况。总之,不能过度信任和依赖「跨城专线」。
阿里巴巴早期的多活方案就是基于上述这种方案,如早期阿里为了应对双11购物,杭州机房与上海机房采用的就是伪同城多活,应用层多活,2个应用节点同时写一个机房数据,并且很好的解决双11大流量购物需求。
严格来讲,这种多活方案只是做到了应用多活,没有做到数据存储层的多活,属于伪异地双活方案。
要真正的做到异地双活,需要在存储层做一定的改造,两个机房的存储必须都是「主库」,而且两个机房的数据还要「互相同步」数据,即客户端无论写哪一个机房,都能把这条数据同步到另一个机房。因为只有两个机房都拥有「全量数据」,才能支持任意切换机房,持续提供服务。
具体部署架构如下:
真正的异地双活需要解决的最核心的问题是数据同步的问题,MySQL 本身就提供了双主架构,它支持双向复制数据,但平时用的并不多。而且 Redis、MongoDB 等数据库并没有提供这个功能,所以,你必须开发对应的「数据同步中间件」来实现双向同步的功能。
此外,除了数据库这种有状态的软件之外,你的项目通常还会使用到消息队列,例如 RocketMQ、Kafka,这些也是有状态的服务,所以它们也需要开发双向同步的中间件,支持任意机房写入数据,同步至另一个机房。
业界也开源出了很多数据同步中间件,例如阿里的 Canal、RedisShake、MongoShake,可分别在两个机房同步 MySQL、Redis、MongoDB 数据,阿里早期的数据同步使用的是DRC,目前阿里云上有相应的商业化产品DTS,支持关系型数据库、NoSQL、大数据(OLAP)等数据源实时同步。
基于上述数据同步的中间件,具体部署方案如下:
使用数据同步的中间件解决了数据同步的问题,但同时带来了一个很严重的问题,就是数据冲突的问题,两个机房操作同一条数据记录,尤其对于交易来说数据一致性要求比较高的应用而言,这是一个必须要解决的问题。
阿里实施异地双活的解决方案,称之为单元化,接下来具体讲一下何为单元化。
具体来讲就是,要在最上层就把用户「区分」开,部分用户请求固定打到北京机房,其它用户请求固定打到上海 机房,进入某个机房的用户请求,之后的所有业务操作,都在这一个机房内完成,从根源上避免「跨机房」。
所以这时,你需要在接入层之上,再部署一个「路由层」(通常部署在云服务器上),自己可以配置路由规则,把用户「分流」到不同的机房内。
具体部署架构:
常见的路由方案:
按业务类型分片
举例:假设我们一共有 4 个应用,北京和上海机房都部署这些应用。但应用 1、2 只在北京机房接入流量,在上海机房只是热备。应用 3、4 只在上海机房接入流量,在北京机房是热备。
这样一来,应用 1、2 的所有业务请求,只读写北京机房存储,应用 3、4 的所有请求,只会读写上海机房存储。
直接哈希分片
最上层的路由层,会根据用户 ID 计算「哈希」取模,然后从路由表中找到对应的机房,之后把请求转发到指定机房内。
举例:一共 200 个用户,根据用户 ID 计算哈希值,然后根据路由规则,把用户 1 - 100 路由到北京机房,101 - 200 用户路由到上海机房,这样,就避免了同一个用户修改同一条数据的情况发生。
按地理位置分片
这种方案,非常适合与地理位置密切相关的业务,例如打车、外卖服务就非常适合这种方案。
拿外卖服务举例,你要点外卖肯定是「就近」点餐,整个业务范围相关的有商家、用户、骑手,它们都是在相同的地理位置内的。
针对这种特征,就可以在最上层,按用户的「地理位置」来做分片,分散到不同的机房。
举例:北京、河北地区的用户点餐,请求只会打到北京机房,而上海、浙江地区的用户,请求则只会打到上海机房。这样的分片规则,也能避免数据冲突。
总之,分片的核心思路在于,让同一个用户的相关请求,只在一个机房内完成所有业务闭环,不再出现跨机房访问,这就是所谓的单元化,阿里巴巴的淘系异地多活基于用户ID的路由实现的单元化。
两个机房就可以都接收「读写」流量(做好分片的请求),底层存储保持「双向」同步,两个机房都拥有全量数据,当任意机房故障时,另一个机房就可以「接管」全部流量,实现快速切换,至此,我们才算实现了真正的异地双活。
真正实施异地多活的成本是非常高的,这里面涉及到路由规则、路由转发、数据同步中间件、数据校验兜底策略,不仅需要开发强大的中间件,同时还要业务配合改造(业务边界划分、依赖拆分)等一些列工作,没有足够的人力物力,这套架构很难实施,不过随着云计算的技术发展,目前对于一些中小企业来讲,在一定程度降低了实施异地多活的成本。
异地多活
理解了异地双活,那「异地多活」顾名思义,就是在异地双活的基础上,部署多个机房即可。架构变成了这样:
这些服务按照「单元化」的部署方式,可以让每个机房部署在任意地区,随时扩展新机房,你只需要在最上层定义好分片规则就好了。
但这里还有一个小问题,随着扩展的机房越来越多,当一个机房写入数据后,需要同步的机房也越来越多,这个实现复杂度会比较高。
所以业界又把这一架构又做了进一步优化,把「网状」架构升级为「星状」:
这种方案必须设立一个中心机房,任意机房写入数据后,都只同步到中心机房,再由中心机房同步至其它机房。
这样做的好处是,一个机房写入数据,只需要同步数据到中心机房即可,不需要再关心一共部署了多少个机房,实现复杂度大大简化。
但与此同时,这个中心机房的稳定性要求会比较高。不过也还好,即使中心机房发生故障,我们也可以把任意一个机房,提升为中心机房,继续按照之前的架构提供服务。
异地多活方案的优劣:
优势:
容灾能力大幅度提高,服务异地多活,数据异地多活。
理论上系统服务可以水平扩展,异地多机房突破大幅度提升整体容量,理论上不会有性能担忧。
将用户流量切分到多个机房和地区去,有效能减少机房和地区级别的故障影响范围。
劣势:
架构非常复杂,部署和运维成本很高,需要对公司依赖的中间件、储存做多方面能力改造。
对业务系统有一定的侵入性,由于单元化影响服务调用或者写入数据要路由到对应的单元,业务系统需要设置路由标识(例如uid)。
无法完全避免跨单元、跨地区调用服务,例如上面的转账业务。我们要做的是尽力避免跨地区的服务调用。
全球化多活
全球化多活指的是业务部署在不同国家的多个机房。相比跨城异地,跨国异地的距离就更远了,因此数据同步的延时会更长,正常情况下可能就有几秒钟了。这种程度的延迟已经无法满足异地多活标准的第一条:“正常情况下,用户无论访问哪一个地点的业务系统,都能够得到正确的业务服务”。例如,假设有一个微博类网站,分别在中国的上海和美国的纽约都建了机房,用户 A 在上海机房发表了一篇微博,此时如果他的一个关注者 B 用户访问到美国的机房,很可能无法看到用户 A 刚刚发表的微博。虽然跨城异地也会有此类同步延时问题,但正常情况下几十毫秒的延时对用户来说基本无感知的;而延时达到几秒钟就感觉比较明显了。
因此,跨国异地的“多活”,和跨城异地的“多活”,实际的含义并不完全一致。跨国异地多活的主要应用场景一般有这几种情况:
为不同地区用户提供服务
亚马逊中国是为中国用户服务的,而亚马逊美国是为美国用户服务的,亚马逊中国的用户如果访问美国亚马逊,是无法用亚马逊中国的账号登录美国亚马逊的。
只读类业务做多活
谷歌的搜索业务,由于用户搜索资料时,这些资料都已经存在于谷歌的搜索引擎上面,无论是访问英国谷歌,还是访问美国谷歌,搜索结果基本相同,并且对用户来说,也不需要搜索到最新的实时资料,跨国异地的几秒钟网络延迟,对搜索结果是没有什么影响的。
真正意义上的全球化多活,实施起来是非常困难的,因为跨国的延时问题不是秒级延时问题,更重要的跨国专线的稳定性,类似Facebook、Google这种对延时要求不敏感的业务相对来说还好一些,对于数据一致性要求比较高的业务很难做全球化多活,同时涉及到各国对于数据安全合规要求以及GDPR要求,很多国家的数据不允许回流到其他国家的,也就意味着不能回流到主数据中心的。
实施异地多活
要想真正实现异地多活,还需要遵循一些原则,例如业务梳理、业务分级、数据分类、数据最终一致性保障、机房切换一致性保障、异常处理等等。同时,相关的运维设施、监控体系也要能跟得上才行。
宏观上需要考虑业务(微服务部署、依赖、拆分、SDK、Web 框架)、基础设施(服务发现、流量调度、持续集成、同步中间件、自研存储),微观上要开发各种中间件,还要关注中间件的高性能、高可用、容错能力,其复杂度之高,尤其对于一些中小企业来讲成本非常高的。
具体如何实施异地多活,可以分为如下4步:
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、ActiveMQ、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% 的用户的损失。常见的补偿措施有送用户代金券、礼包、礼品、红包等,有时为了赢得用户口碑,付出的成本可能还会比较大,但综合最终的收益来看还是很值得的。例如暴雪《炉石传说》2017 年回档故障,暴雪给每个用户大约价值人民币 200 元的补偿,结果玩家都求暴雪再来一次回档,形象地说明了玩家对暴雪补偿的充分认可。
总结
异地多活,从整个业界的做法上来讲,主要有几家公司,比如Google、Facebook,这些是技术强悍切比较典型的,Google做到了全球多个数据中心,都是多活的。但是Google具体怎么做的,也没有多少人了解。另外就是Facebook,我们相对更了解一些,Facebook在做多个数据中心时,比如说美国和欧洲两个数据中心,确实都在支撑流量。但是欧洲的用户有可能需要访问美国的数据中心,当出现这种状况时,整个用户体验不好。国内目前将异地多活做成熟的公司比较多,像阿里的单元化异地多活、饿了么、新浪微博、京东购物等,都已经做得非常成熟。
多活的技术成本非常高,每家公司都不断在成本与业务之间综合平衡各种利弊,选择最好的方式服务业务。总之, 多活技术并不能100%解决全部业务多活,只能尽量保证绝大部分用户的核心业务异地多活。
现代多活方案常常会利用云计算平台的低部署和弹性运营成本与云计算平台搭建混合云环境,比如阿里云提供了DTS能够支撑关系型数据库、NoSQL、大数据(OLAP)等数据源实时同步,同时提供了GSLB以及智能DNS解析,云解析 DNS 基于智能 DNS 解析做就近访问。目前主流的 DNS 解析服务都能够提供较为智能的解析线路,比如州级别、地域级别、国家级别等,在一定程度上降低了实施异地多活的成本。
分布式多活数据中心与云计算建设的思路既有相同之处也有差别,云的形成可以基于数据中心的分布式技术,建设模型更接近互联网数据中心,而分布式多活数据中心的实现和实践门槛相对要低,用户在建设运维时更多的会关注于自身业务联系性的要求与业务的快速响应及IT建设的持续优化,对复杂的企业级应用提供更好的支撑,使得IT建设更多的基于自身现有资源和能力。总之使用混合方式,而不盲目追求先进,体现了企业对于自身IT建设的把握与未来方向的掌控,是大型企业数据中心、大型多活系统持续稳健前行的必经之路。
灾备高可用方案总结
1、同城灾备分为「冷备」和「热备」,冷备只备份数据,不提供服务,热备实时同步数据,并做好随时切换的准备
2、同城双活比灾备的优势在于,两个机房都可以接入「读写」流量,提高可用性的同时,还提升了系统性能。虽然物理上是两个机房,但「逻辑」上还是当做一个机房来用
3、两地三中心是在同城双活的基础上,额外部署一个异地机房做「灾备」,用来抵御「城市」级别的灾害,但启用灾备机房需要时间
4、异地双活才是抵御「城市」级别灾害的更好方案,两个机房同时提供服务,故障随时可切换,可用性高。但实现也最复杂,理解了异地双活,才能彻底理解异地多活
5、异地多活是在异地双活的基础上,任意扩展多个机房,不仅又提高了可用性,还能应对更大规模的流量的压力,扩展性最强,是实现高可用的最终方案
6、全球化多活指的是是业务部署在不同国家的多个机房,为不同地区的用户提供服务,为全球用户提供只读服务。
具体实施经验总结
1、异地多活虽然功能很强大,但也不是每个业务不管三七二十一都要上异地多。
2、如果业务规模很大,能够做异地多活的情况下尽量实现异地多活。
3.异地多活设四大技巧
保证核心业务的异地多活。
保证核心数据最终一致性。
采用多种手段同步数据。
只保证绝大部分用户的异地多活。
4.接口级故障的主要应对方案:降级、熔断、限流、排队。
降级的核心思想就是丢车保帅,优先保证核心业务。
限流指只允许系统能够承受的用户量进来访问,超出系统访问能力
reference:
http://kaito-kidd.com/2021/10/15/what-is-the-multi-site-high-availability-design/
https://www.infoq.cn/article/gqyk1h46thu4mbqpardw
https://segmentfault.com/a/1190000024447073