异地多活架构
异地指地理位置上的不同,多活指不同地理位置上的系统都能够提供业务服务。
判断标准:
- 正常情况下,用户无论访问哪一个地点的业务系统,都能够得到正确的业务服务。
- 某地异常时,用户访问其他地方正常的业务系统,能够得到正确的业务服务。
异地多活的代价:
- 系统复杂度会有质的变化。
- 成本大大增加。
架构模式
1. 同城异区
部署在同一个城市不同区的机房,用专用网络连接。
同城异区两个机房距离一般就是几十千米,网络传输速度几乎和同一个机房相同,降低了系统复杂度、成本。
这个模式无法解决极端的灾难情况,例如某个城市的地震、水灾,此方式是用来解决一些常规故障的,例如机房的火灾、停电、空调故障。
2. 跨城异地
部署在不同城市的多个机房,距离要远一些,例如北京和广州。
此模式就是用来处理极端灾难情况的,例如城市的地震、相邻城市的大停电。
跨城异地主要问题就是网络传输延迟,例如北京到广州,正常情况下的RTT(Round-Trip Time 往返时延)是50毫秒,当遇到网络波动等情况,会升到500毫秒甚至1秒,而且会有丢包问题。
物理距离必然导致数据不一致,这就得从“数据”特性来解决,如果是强一致性要求的数据(如存款余额),就无法做异地多活。
举例,存款余额支持跨城异地多活,部署在北京和广州,当光缆被挖断后,会发生:
- 用户A余额有10000,北京和广州是一致的。
- A在广州机房给B转5000,广州余额为5000,由于网络不通,北京此时的余额为10000。
- A在北京发现余额还是10000,给C转10000,由于网络不通,广州的余额为5000。
- A在广州又可以给D转5000。
这就出事儿了,所以这类数据不会做跨城异地多活,只能用同城异区架构,因为同城的网络环境要好很多,可以搭建多条互联通道,成本也不会太高。
跨城异地模式适用于对数据一致性要求不高的场景,例如:
- 用户登录,数据不一致时重新登录即可。
- 新闻网站,一天内新闻数据变化较少。
- 微博网站,即使丢失一点微博或评论数据也影响不大。
3. 跨国异地
部署在不同国家的多个机房。
此模式的延时就更长了,正常情况也得几秒,无法满足正常的业务访问。
所以,跨国异地多活适用于:
- 为不同地区用户提供服务
例如,亚马逊美国是为美国用户服务的,亚马逊中国的账号是无法登录美国亚马逊的。
- 只读类业务
例如谷歌的搜索,不管用户在哪个国家搜索,得到的结果基本相同,对用户来说,跨国异地的几秒延迟,对搜索结果没什么影响。
跨城异地多活设计技巧
1. 保证核心业务的异地多活
思维误区:要保证所有业务都能异地多活。
假设用户子系统,负责注册、登录、用户信息这3个业务,由于有海量用户,所以对用户进行分区,分配到不同数据中心,正常情况下某个用户属于某个主分区,并在其他分区也有备份,通过hash计算得出属于哪个中心。
如果想要保证注册业务多活,可能会有问题,例如,A中心注册了用户,数据还未同步到B中心时A宕了,为了支持多活,需要可以让用户到B中心重新注册,但一个手机号只能注册一个账号,A恢复后就有冲突了。
如果要保证用户信息业务多活,也会有问题,例如,A、B两个中心在异常情况下都修改了用户信息,如何处理冲突?
可以发现,注册、登录、用户信息这3个业务都支持多活的话,是非常难的,有的问题甚至是无解的。解决的方法就是:优先实现核心业务的异地多活。
这个示例中,“登录”才是核心业务,例如系统的日活是1000万,每天的注册可能是几万,修改用户信息的可能还不到1万,但登录是1000万,很明显要保证登录的异地多活。
2. 保证核心数据最终一致性
思维误区:要保证所有数据实时同步。
由于物理上的限制,所有数据都实时同步,是一个无法达到的目标。
必须要尽量减少数据同步,只同步核心业务相关的数据。
例如上面的例子,登录产生的token或session信息,数据量很大,实际上不需要同步到其他中心,即使丢失了重新登录就可以了,会影响用户体验,但是可以接受的。
3. 采用多种手段同步数据
思维误区:只使用存储系统的同步功能。
存储系统本身就有强大的同步功能,例如 mysql redis 都可以很好的实现同步,但某些场景下是无法满足需要的,所以要使用多种手段配合,例如:
- 消息队列
创建账号后,将账号数据通过消息队列同步到其他业务中心。
- 二次读取
例如用户在A中心注册了,然后访问了B中心,此时B还没有拿到账号数据,为了解决这个问题,B中心在读取本地数据失败时,可以根据路由规则,再去A中心访问一次。
- 回源读取
例如session数据没有同步,用户在A中心登录,B中心可以拿着session id到A中心请求session数据。
4. 只保证绝大部分用户的异地多活
思维误区:要保证业务 100% 可用。
物理规律决定了异地多活无法保证100%的业务可用。
以转账业务为例,在北京和上海两个中心实现了实时转账的异地多活,在异常情况下会出现问题,例如用户有一万存款,在北京给人转了一万,又到上海给人转了一万。
所以,无法做到实时转账的异地多活,需要通过特殊业务受到实现。
例如,除了“实时转账”外,还提供“转账申请”业务,用户在上海提交了转账请求,并不立即转账,而是后台异步处理,如果发现北京中心不可用,就等待重试,北京恢复后,如果发现余额不足就转账失败。
这个方式牺牲了一些用户体验,本来一次完成的操作变为了2次,一次提交转账申请,另一次是确认转账结果。
对于用户体验,可以采取一些补偿措施,例如:
- 公告
例如由于xxx原因导致您的不便,技术哥哥正在紧急处理等等。
- 事后补偿
例如送代金券、小礼品等。
- 补充体验
例如上面的转账例子,可以在转账结果出来后给用户发个短信,减少用户不时的登录查看。
小结