说在前面
在40岁老架构师尼恩的数千读者群中,一直在指导大家简历和职业升级,前几天,指导了一个华为老伙伴的简历,小伙伴的优势在异地多活,但是在简历指导的过程中,尼恩发现: 异地多活的概念、异地多活的架构、非常重要,但是小伙伴却对整个异地多活的体系,不是太清晰。
异地多活的概念有很杂乱,像什么同城双活、两地三中心、三地五中心等等
这里 ,尼恩 站在 得物 异地多活架构(得物架构师 YINJIHUAN)的基础上, 给大家对异地多活,做一个起底式的 、系统化、穿透式的介绍。
并且,把此文的异地多活架构,和尼恩其他的架构文章一起,组成一个架构知识系统,帮助大家实现你的 架构自由:
《阿里二面:千万级、亿级数据,如何性能优化? 教科书级 答案来了》
《峰值21WQps、亿级DAU,小游戏《羊了个羊》是怎么架构的?》
以上的架构系列文章,非常重要,建议大家多多看看。
以上文章的PDF版本,都可以在《技术自由圈》公众号找尼恩来获取。
言归正传。
本文目录
1. 什么是异地多活
异地多活的概念很多,像什么同城双活、两地三中心、三地五中心等等概念。
要想理解异地多活,需要从架构设计的3高原则说起。
架构设计的3高原则
现如今,开发一个软件系统,对其要求越来越高,如果你了解一些「架构设计」的要求,就知道一个好的软件架构应该遵循以下 3 个原则:
- 高性能
- 高并发
- 高可用
高性能意味着系统拥有更大流量的处理能力,更低的响应延迟。
例如 1 秒可处理 10W 并发请求,接口响应时间 5 ms 等等。
高并发表示系统在迭代新功能时,能以最小的代价去扩展,系统遇到流量压力时,可以在不改动代码的前提下,去扩容系统。
高可用通常用 2 个指标来衡量:
- 平均故障间隔 MTBF(Mean Time Between Failure):表示两次故障的间隔时间,也就是系统「正常运行」的平均时间,这个时间越长,说明系统稳定性越高
- 故障恢复时间 MTTR(Mean Time To Repair):表示系统发生故障后「恢复的时间」,这个值越小,故障对用户的影响越小
可用性与这两者的关系:
可用性(Availability)= MTBF / (MTBF + MTTR) * 100%
这个公式得出的结果是一个「比例」,通常我们会用「N 个 9」来描述一个系统的可用性。

从这张图你可以看到,要想达到 4 个 9 以上的可用性,一年的不可以时间为 52分钟,平均每天故障时间必须控制在 10 秒以内。
系统发生故障其实是不可避免的,尤其是规模越大的系统,发生问题的概率也越大。
这些故障一般体现在 3 个方面:
- 硬件故障:CPU、内存、磁盘、网卡、交换机、路由器
- 软件问题:代码 Bug、版本迭代
- 不可抗力:地震、水灾、火灾、战争
这些风险随时都有可能发生。所以,在面对故障时,我们的系统能否以「最快」的速度恢复,就成为了可用性的关键。
常见的多活方案
4 个 9 高可用的核心方案就是异地多活
异地多活指分布在异地的多个站点同时对外提供服务的业务场景。
异地多活是高可用架构设计的一种,与传统的灾备设计的最主要区别在于“多活”,即所有站点都是同时在对外提供服务的。
常见的多活方案有同城双活、两地三中心、三地五中心等多种技术方案,
常见方案1:同城双活
同城双活是在同城或相近区域内建立两个机房。同城双机房距离比较近,通信线路质量较好,比较容易实现数据的同步复制 ,保证高度的数据完整性和数据零丢失。
同城两个机房各承担一部分流量,一般入口流量完全随机,内部RPC调用尽量通过就近路由闭环在同机房,相当于两个机房镜像部署了两个独立集群,数据仍然是单点写到主机房数据库,然后实时同步到另外一个机房。
下图展示了同城双活简单部署架构,当然一般真实部署和考虑问题要远远比下图复杂。

服务调用基本在同机房内完成闭环,数据仍然是单点写到主机房数据储存,然后实时同步复制到同城备份机房。
当机房A出现问题时候运维人员只需要通过GSLB或者其他方案手动更改路由方式将流量路由到B机房。
同城双活可有效用于防范火灾、建筑物破坏、供电故障、计算机系统及人为破坏引起的机房灾难。
同城双活中的核心组件GSLB的原理,可以参见 尼恩的高并三部曲 之三《Java高并发核心编程 卷3 加强版》PDF。
常见方案2:两地三中心
所谓两地三中心是指 同城双中心 + 异地灾备中心。
异地灾备中心是指在异地的城市建立一个备份的灾备中心,用于双中心的数据备份,数据和服务平时都是冷的,
当双中心所在城市或者地区出现异常而都无法对外提供服务的时候,异地灾备中心可以用备份数据进行业务的恢复。

两地三中心方案特点
优势
- 服务同城双活,数据同城灾备,同城不丢失数据情况下跨机房级别容灾。
- 架构方案较为简单,核心是解决底层数据双活,由于双机房距离近,通信质量好,底层储存例如mysql可以采用同步复制,有效保证双机房数据一致性。
- 灾备中心能防范同城双中心同时出现故障时候利用备份数据进行业务的恢复。
劣势
- 数据库写数据存在跨机房调用,在复杂业务以及链路下频繁跨机房调用增加响应时间,影响系统性能和用户体验。
- 服务规模足够大(例如单体应用超过万台机器),所有机器链接一个主数据库实例会引起连接不足问题。
- 出问题不敢轻易将流量切往异地数据备份中心,异地的备份数据中心是冷的,平时没有流量进入,因此出问题需要较长时间对异地灾备机房进行验证。
同城双活和两地三中心建设方案建设复杂度都不高,两地三中心相比同城双活有效解决了异地数据灾备问题,但是依然不能解决同城双活存在的多处缺点,想要解决这两种架构存在的弊端就要引入更复杂的解决方案去解决这些问题。
常见方案2:三地五中心
三地五中心和两地三中心 的架构差不太多,这里不做展开,
有兴趣的小伙伴,可以来尼恩的疯狂创客圈 高并发社群交流。
异地多活3大挑战

1、数据同步延迟挑战
(1)应用要走向异地,首先要面对的便是物理距离带来的延时。
如果某个应用请求需要在异地多个单元对同一行记录进行修改,为满足异地单元间数据库数据的一致性和完整性,需要付出高昂的时间成本。
(2)解决异地高延时即要做到单元内数据读写封闭,不能出现不同单元对同一行数据进行修改,所以我们需要找到一个维度去划分单元。
(3)某个单元内访问其他单元数据需要能正确路由到对应的单元,例如A用户给B用户转账,A用户和B用户数据不在一个单元内,对B用户的操作能路由到相应的单元。
(4)面临的数据同步挑战,对于单元封闭的数据需全部同步到对应单元,对于读写分离类型的,我们要把中心的数据同步到单元。
2、单元化解耦挑战
所谓单元(下面我们用RZone代替),是指一个能完成所有业务操作的自包含集合,在这个集合中包含了所有业务所需的所有服务,以及分配给这个单元的数据。
单元化架构就是把单元作为系统部署的基本单位,在全站所有机房中部署数个单元,每个机房里的单元数目不定,任意一个单元都部署了系统所需的所有的应用。
单元化架构下,服务仍然是分层的,不同的是每一层中的任意一个节点都属于且仅属于某一个单元,上层调用下层时,仅会选择本单元内的节点。
选择什么维度来进行流量切分,要从业务本身入手去分析。
例如电商业务和金融的业务,最重要的流程即下单、支付、交易流程,通过对用户id进行数据切分拆分是最好的选择,买家的相关操作都会在买家所在的本单元内完成。
对于商家相关操作则无法进行单元化,需要按照下面介绍的非单元化模式去部署。
当然用户操作业务并非完全能避免跨单元甚至是跨机房调用,例如两个买家A和B转账业务,A和B所属数据单元不一致的时候,对B进行操作就需要跨单元去完成,后面我们会介绍跨单元调用服务路由问题。
3、流量的路由挑战
- 流量调度,系统部署过去后流量怎么跟着怎么过去。
- 流量自闭环。由于距离的原因,跨地域的物理延时是没法避免的,流量过去之后怎么保证所有的操作都在本地完成,如果做不到那怎么将这种延时影响降到最低。
- 容灾切流。当某个机房出现故障时,如何快速把流量无损地切至其他机房。这里并不是说简单把流量切过去就完事,由于数据在多区域同步,流量切过去之后能否保证数据的一致性?
2. 得物APP的异地多活改造
2.1得物APP异地多活基础改造
改造之前的单机房架构
了解改造点之前我们先来看下目前单机房的现状是什么样子,才能更好的帮助大家去理解为什么要做这些改造。

如上图所示,客户端的请求进来会先到SLB(负载均衡),然后到我们内部的网关,通过网关再分发到具体的业务服务。
业务服务会依赖Redis, Mysql, MQ, Nacos等中间件。
改造之后的目标
既然做异地多活,那么必然是在不同地区有不同的机房,比如中心机房,单元机房。
所以我们要实现的效果如下图所示:

最低0.47元/天 解锁文章
998

被折叠的 条评论
为什么被折叠?



