Skip to content
0

异地多活架构

异地多活指在不同地理位置上的系统都能提供业务服务,当某个地方的业务异常时,用户也能正常访问其它地方的业务服务。

区别于备份,通常情况下,备份是不提供服务的,如果要提供服务,则需要大量的人工干预和操作。

异地多活虽然很强大,但不是每个业务都需要,毕竟其复杂性和成本都较高。例如,常见的新闻网站、博客站点等,如果无法承受异地多活所带来的复杂性和成本,是可以不做异地多活的,只需要做备份即可。因为这类业务即使中断,对用户影响也不是很大。新闻网站不能看了,用户可以换个新闻网站。但像支付这类业务,就要做异地多活了。

当然,如果业务规模大,还是要尽量做异地多活。毕竟大规模的业务通常伴随诸如广告费等衍生收入,出现异常对用户的体验也不好,影响网站口碑。

架构模式

同城异区

同城异区指将业务部署在同一个城市但不同区的机房中,两个机房通过高速网络连接在一起,达到近似一个本地机房的效果。这样的设计大大降低了复杂度,减少了异地多活设计和实现的复杂度和成本。

同城异区是应对机房级故障的最优架构。

跨城异地

跨城异地指将业务部署在不同城市的机房中。例如,将业务部署在北京和广州的机房,而不是广州和深圳的机房。

跨城异地距离较远带来的网络传输延时,给异地多活架构设计带来较高的复杂度。如果要做到真正意义上的多活,业务系统需要考虑部署在不同地点的两个机房,在数据短时间不一致的情况下,还能够正常提供业务。这就引入了一个看似矛盾的地方:数据不一致业务肯定不会正常,但跨城异地肯定会导致数据不一致。

如何解决这个问题呢?重点还是在“数据”上,即根据数据的特性来做不同的架构。如果是强一致性要求的数据,例如银行存款余额、支付宝余额等,这类数据实际上是无法做到跨城异地多活的。

而对数据一致性要求不那么高,或者数据不怎么改变,或者即使数据丢失影响也不大的业务,跨城异地多活就能够派上用场了。例如,用户登录(数据不一致时用户重新登录即可)、新闻类网站(一天内的新闻数据变化较少)、微博类网站(丢失用户发布的微博或者评论影响不大),这些业务采用跨城异地多活,能够很好地应对极端灾难的场景。

跨国异地

跨国异地指的是业务部署在不同国家的多个机房,主要是给不同国家的用户提供服务,或提供只读服务,对架构设计要求不高。

主要应用场景:

  • 为不同国家用户提供服务。

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

  • 只读类业务做多活。

    例如,谷歌的搜索业务,由于用户搜索资料时,这些资料都已经存在于谷歌的搜索引擎上面,无论是访问英国谷歌,还是访问美国谷歌,搜索结果基本相同,并且对用户来说,也不需要搜索到最新的实时资料,跨国异地的几秒钟网络延迟,对搜索结果是没有什么影响的。

综上,跨城异地是最复杂的架构。

跨城异地设计

四大技巧

假设,A和B两个跨城异地的数据中心,有三个业务:用户登入、注册、修改个人信息。为支持海量用户,A和B都有用户数据的备份,用户通过邮箱或手机号注册,通过哈希规则等路由到对应的数据中心。

一、保证核心业务的异地多活

这个系统要保持三个业务都异地多活是很难的:

  • 注册问题

    A中心注册了用户,数据还未同步到B中心,此时A宕机,是否可以让用户在B中心重新注册?答案是否定的,类似一个手机号只能注册一个账号这种规则是核心业务规则,修改核心业务规则的代价非常大,为了架构设计而改变业务规则是得不偿失的。

  • 修改用户信息问题

    A和B中心在异常情况下都进行修改,如何处理冲突?简单的方案是根据时间来合并,但如何保证两个地区的时间完全同步又是一个问题。或者生成一个全局唯一递增ID,这个成本较高,且其本身也要支持异地多活。

注册和修改信息每天的量并不多,而登入才是核心,大量用户不能登入是大问题。而保证登入业务的异地多活是最简单的。因为A和B都有用户的账号密码等数据,A宕机了在B重新登入就好了。

但这又引出一个新问题:A修改了密码,但是数据还未同步到B,此时A宕机,用户用新密码无法登入。

二、保证核心数据最终一致性

异地多活本质上是通过异地的数据冗余,来保证在极端异常的情况下业务也能够正常提供给用户,因此数据同步是异地多活架构设计的核心。

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

矛盾无法解决,只能尽量减少影响:

  • 尽量减少异地多活机房的距离,搭建高速网络。

    成本巨大,一般只有巨头公司才能承担。

  • 尽量减少数据同步,只同步核心业务相关的数据。

    比如,用户登入所产生的 token 或 session 信息,数据量大,但其实并不需要同步到其它业务中,因为这些数据丢失后重新登入就可以再次获取了。虽说需要用户重新登入,但相比同步所有数据带来的代价,这个影响完全可以接受。

  • 保证最终一致性,不保证实时一致性。

    最终一致性在具体实现时,还需要根据不同的数据特征,进行差异化的处理,以满足业务需要。例如,对“账号”信息来说,如果在A机房新注册的用户5分钟内正好跑到B机房了,此时B机房还没有这个用户的信息,为了保证业务的正确,B机房就需要根据路由规则到A机房请求数据。而对“用户信息”来说,5分钟后同步也没有问题,也不需要采取其他措施来弥补,但还是会影响用户体验,即用户看到了旧的用户信息,这个问题怎么解决呢?

三、采用多种手段同步数据

存储系统本身自带的同步功能,在某些场景下是无法满足业务需要的,尤其是异地多机房这种部署,各种各样的异常情况都可能出现,当我们只考虑存储系统本身的同步功能时,就会发现无法做到真正的异地多活。

解决的方案就是拓开思路,避免只使用存储系统的同步功能,可以将多种手段配合存储系统的同步来使用,甚至可以不采用存储系统的同步方案,改用自己的同步方案。

以下为示意方案,实际情况会更加复杂,还要考虑很多其它细节。

  • 消息队列

    这个就不用多说了,常用的数据同步方式。

  • 二次读取方式

    某些情况下可能出现消息队列同步也延迟了,用户在A中心注册,然后访问B中心的业务,此时B中心本地拿不到用户的账号数据。为了解决这个问题,B中心在读取本地数据失败时,可以根据路由规则,再去A中心访问一次(这就是所谓的二次读取,第一次读取本地,本地失败后第二次读取对端),这样就能够解决异常情况下同步延迟的问题。

  • 存储系统的同步方式

    对于密码数据,由于用户改密码频率较低,而且用户不可能在1秒内连续改多次密码,所以通过数据库的同步机制将数据复制到其他业务中心即可,用户信息数据和密码类似。

  • 回源读取方式

    对于登录的session数据,由于数据量很大,我们可以不同步数据;但当用户在A中心登录后,然后又在B中心登录,B中心拿到用户上传的 sessionId 后,根据路由判断 session属于A中心,直接去A中心请求 session数据即可;反之亦然,A中心也可以到B中心去获取 session数据。

  • 重新生成数据方式

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

四、只保证绝大部分用户的异地多活

技巧1中密码不同步导致无法登入的问题和技巧2中用户信息不同步导致用户看到旧数据的问题,这要如何解决呢?

答案是无法保证100%的业务可用性。不要因小失大。

总结

用多种手段,保证绝大部分用户的核心业务异地多活!

四个步骤

1.业务分级

按照一定的标准将业务分级,挑选出核心业务,只为核心业务设计异地多活,降低方案复杂度和实现成本。常见的分级标准有:

  • 访问量大的业务
  • 核心业务
  • 产生大量收入的业务

2.数据分类

挑选出核心业务后,需要对核心业务相关的数据进一步分析,目的在于识别所有的数据及数据特征,这些数据特征会影响后面的方案设计。常见的数据特征分析维度有:

  • 数据量

    包括总的数据量和新增、修改、删除的量。对异地多活架构来说,新增、修改、删除的数据就是可能要同步的数据,数据量越大,同步延迟的几率越高,同步方案需要考虑相应的解决方案。

  • 唯一性

    唯一性指数据是否要求多个异地机房产生的同类数据必须保证唯一。例如用户ID。数据的唯一性影响业务的多活设计,如果数据不需要唯一,那就说明两个地方都产生同类数据是可能的;如果数据要求必须唯一,要么只能一个中心点产生数据,要么需要设计一个数据唯一生成的算法。

  • 实时性

    实时性指如果在A机房修改了数据,要求多长时间必须同步到B机房,实时性要求越高,对同步的要求越高,方案越复杂。

  • 可丢失性

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

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

  • 可恢复性

    可恢复性指数据丢失后,是否可以通过某种手段进行恢复,如果数据可以恢复,至少说明对业务的影响不会那么大,这样可以相应地降低异地多活架构设计的复杂度。

    例如用户发的微博丢失后,用户可以从草稿箱等再发布一条微博,这就是可恢复的;或用户密码丢失,用户可以通过找回密码来重新设置一个新密码,也算是可以恢复的;而如果用户账号丢失,系统也无法通过其它途径来恢复这个账号,这就是不可恢复的数据。

以用户登入业务为例,简单分析如下表所示:

数据数据量唯一性实时性可丢失性可恢复性
用户ID每天新增1万注册用户全局唯一5秒内同步不可丢失不可恢复
用户密码每天1千用户修改密码用户唯一5秒内同步可丢失可重置密码恢复
登入session每天1000万全局唯一无须同步可丢失可重复生成

3.数据同步

确定数据的特点后,我们可以根据不同的数据设计不同的同步方案。常见的数据同步方案有:

  • 存储系统同步:如用户密码。
  • 消息队列:如用户ID。
  • 重复生成:如登入session。

4.异常处理

无论数据同步方案如何设计,一旦出现极端异常的情况,总是会有部分数据出现异常的。例如,同步延迟、数据丢失、数据不一致等。异常处理就是假设在出现这些问题时,系统将采取什么措施来应对。异常处理主要有以下几个目的:

  1. 问题发生时,避免少量数据异常导致整体业务不可用。
  2. 问题恢复后,将异常的数据进行修正。
  3. 对用户进行安抚,弥补用户损失。

常见的异常处理措施有如下几类。

多通道同步

采用多种方式同步数据。比如同时使用存储系统的同步机制和消息队列来同步数据。

设计关键点:

  • 一般情况下,采取两通道即可,采取更多通道理论上能够降低风险,但引入更多的成本。
  • 同步通道不能采用相同的网络。
  • 同步的数据是可以重复覆盖的,即数据同步没有先后关系,最终结果一致。如新建账号就符合这个标准,而密码数据则不符合。
同步和访问结合

这里的访问是指异地机房通过系统提供的接口进行数据访问。例如,业务部署在异地两个机房A和B,B机房的业务可以通过接口来访问A机房的系统获取账号信息。

设计关键点:

  • 和多通道类似,不能走同一条网络。
  • 数据有路由规则,可以根据数据来推断应该访问哪个机房的接口来读取数据。
  • 由于有同步通道,优先读取本地数据,本地数据无法读取到再通过接口去访问,这样可以大大降低跨机房的异地接口访问数量,适合于实时性要求非常高的数据。
日志记录

日志记录主要用于用户故障恢复后对数据进行恢复,其主要方式是每个关键操作前后都记录相关一条日志,然后将日志保存在一个独立的地方,当故障恢复后,拿出日志跟数据进行对比,对数据进行修复。

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

  • 服务器上保存日志,数据库中保存数据,这种方式可以应对单台数据库服务器故障或者宕机的情况。
  • 本地独立系统保存日志,这种方式可以应对某业务服务器和数据库同时宕机的情况。例如,服务器和数据库部署在同一个机架,或者同一个电源线路上,就会出现服务器和数据库同时宕机的情况。
  • 日志异地保存,这种方式可以应对机房宕机的情况。

上面不同的日志保存方式,应对的故障越严重,方案本身的复杂度和成本就会越高,实际选择时需要综合考虑成本和收益情况。

用户补偿

无论多么完美的方案,故障的场景下总是可能有一小部分用户业务上出问题,系统无法弥补这部分用户的损失。但我们可以采用人工的方式对用户进行补偿,弥补用户损失,培养用户的忠诚度。简单来说,系统的方案是为了保证99.99%的用户在故障的场景下业务不受影响,人工的补偿是为了弥补0.01%的用户的损失。