架构专题《五》——异地多活【灾备1】

导读:作为大型运营商,结合身边的外包商(华为、亚信)等,平时和互联网朋友撸串拉呱的话题,灾备是必须的。灾备是个很大的话题,划分的维度也不同。异地多活,作为一种高可用部署架构,成为大中型互联网公司的选择。像大家熟知的大型互联网公司,如阿里、腾讯、百度、网易、新浪等等都已经完成了异地多活的技术重构。

可以说,异地多活是互联网公司业务规模扩大后所必然要经历的阶段。那么如何解决高可用异地多活呢?

一、有状态服务

后台服务可以划分为两类,有状态和无状态。高可用对于无状态的应用来说是比较简单的,无状态的应用,只需要通过 F5 或者任何代理的方式就可以很好的解决。

后文描述的主要是针对有状态的服务进行分析。服务端进行状态维护主要是通过磁盘或内存进行保存,比如 MySQL 数据库,Redis 等内存数据库。

除了这两种类型的维护方式,还有 JVM 的内存的状态维持,但 JVM 的状态生命周期通常很短。

二、高可用的一些解决方案

高可用,从发展来看,大致经过了这几个过程:

  1. 冷备

  2. 双机热备

  3. 同城双活

  4. 异地双活

  5. 异地多活

在聊异地多活的时候,还是先看一些其他的方案,这有利于我们理解很多设计的缘由。 

2.1、冷备

 冷备,通过停止数据库对外服务的能力,通过文件拷贝的方式将数据快速进行备份归档的操作方式。

 简而言之,冷备,就是复制粘贴,在 Linux 上通过 cp 命令就可以很快完成。可以通过人为操作,或者定时脚本进行。 

有如下好处:

  1. 简单

  2. 快速备份(相对于其他备份方式)

  3. 快速恢复。只需要将备份文件拷贝回工作目录即完成恢复过程(亦或者修改数据库的配置,直接将备份的目录修改为数据库工作目录)。更甚,通过两次 mv 命令就可瞬间完成恢复。

  4. 可以按照时间点恢复。比如,几天前发生的拼多多优惠券漏洞被人刷掉很多钱,可以根据前一个时间点进行还原,“挽回损失”。

以上的好处,对于以前的软件来说,是很好的方式。但是对于现如今的很多场景,已经不好用了,因为:

  1. 服务需要停机。N 个 9 肯定无法做到了。然后,以前我们的停机冷备是在凌晨没有人使用的时候进行,但是现在很多的互联网应用已经是面向全球了,所以,任何时候都是有人在使用的。

  2. 数据丢失。如果不采取措施,那么在完成了数据恢复后,备份时间点到还原时间内的数据会丢失。

    传统的做法,是冷备还原以后,通过数据库日志手动恢复数据。比如通过 redo 日志,更甚者,我还曾经通过业务日志去手动回放请求恢复数据。恢复是极大的体力活,错误率高,恢复时间长。

  3. 冷备是全量备份。全量备份会造成磁盘空间浪费,以及容量不足的问题,只能通过将备份拷贝到其他移动设备上解决。

    所以,整个备份过程的时间其实更长了。想象一下每天拷贝几个T的数据到移动硬盘上,需要多少移动硬盘和时间。并且,全量备份是无法定制化的,比如只备份某一些表,是无法做到的。

如何权衡冷备的利弊,是每个业务需要考虑的。 现如今离光大的程序员们已经很遥远了。

2.2、双机热备

热备,和冷备比起来,主要的差别是不用停机,一边备份一边提供服务。但还原的时候还是需要停机的。由于我们讨论的是和存储相关的,所以不将共享磁盘的方式看作双机热备。

①Active/Standby 模式

相当于 1 主 1 从,主节点对外提供服务,从节点作为 backup。通过一些手段将数据从主节点同步到从节点,当故障发生时,将从节点设置为工作节点。数据同步的方式可以是偏软件层面,也可以是偏硬件层面的。

偏软件层面的,比如 MySQL 的 master/slave 方式,通过同步 binlog 的方式;sqlserver 的订阅复制方式。

 偏硬件层面,通过扇区和磁盘的拦截等镜像技术,将数据拷贝到另外的磁盘。偏硬件的方式,也被叫做数据级灾备;偏软件的,被叫做应用级灾备。后文谈得更多的是应用级灾备。

②双机互备

 本质上还是 Active/Standby,只是互为主从而已。双机互备并不能工作于同一个业务,只是在服务器角度来看,更好的压榨了可用的资源。

 比如,两个业务分别有库 A 和 B,通过两个机器 P 和 Q 进行部署。那么对于 A 业务,P 主 Q 从,对于 B 业务,Q 主 P 从。

 整体上看起来是两个机器互为主备。这种架构下,读写分离是很好的,单写多读,减少冲突又提高了效率。 

其他的高可用方案还可以参考各类数据库的多种部署模式,比如 MySQL 的主从、双主多从、MHA;Redis 的主从,哨兵,Cluster 等等。

2.3、同城双活

前面讲到的几种方案,基本都是在一个局域网内进行的。业务发展到后面,有了同城多活的方案。

和前面比起来,不信任的粒度从机器转为了机房。这种方案可以解决某个 IDC 机房整体挂掉的情况(停电,断网等)。

同城双活其实和前文提到的双机热备没有本质的区别,只是“距离”更远了,基本上还是一样(同城专线网速还是很快的)。双机热备提供了灾备能力,双机互备避免了过多的资源浪费。

在程序代码的辅助下,有的业务还可以做到真正的双活,即同一个业务,双主,同时提供读写,只要处理好冲突的问题即可。需要注意的是,并不是所有的业务都能做到。

业界更多采用的是两地三中心的做法。远端的备份机房能更大的提供灾备能力,能更好的抵抗地震,恐袭等情况。双活的机器必须部署到同城,距离更远的城市作为灾备机房。

灾备机房是不对外提供服务的,只作为备份使用,发生故障了才切流量到灾备机房;或者是只作为数据备份。原因主要在于:距离太远,网络延迟太大。

图 1:两地三中心

 

如上图,用户流量通过负载均衡,将服务 A 的流量发送到 IDC1,服务器集 A;将服务 B 的流量发送到 IDC2,服务器 B。

同时,服务器集 a 和 b 分别从 A 和 B 进行同城专线的数据同步,并且通过长距离的异地专线往 IDC3 进行同步。

当任何一个 IDC 当机时,将所有流量切到同城的另一个 IDC 机房,完成了failover。

当城市 1 发生大面积故障时,比如发生地震导致 IDC1 和 2 同时停止工作,则数据在 IDC3 得以保全。

同时,如果负载均衡仍然有效,也可以将流量全部转发到 IDC3 中。不过,此时 IDC3 机房的距离非常远,网络延迟变得很严重,通常用户的体验的会受到严重影响的。

图 2:两地三中心主从模式

上图是一种基于 Master-Slave 模式的两地三中心示意图。城市 1 中的两个机房作为 1 主 1 从,异地机房作为从。

也可以采用同城双主+Keepalived+VIP 的方式,或者 MHA 的方式进行failover。但城市 2 不能(最好不要)被选择为 Master。

2.4、异地双活 

同城双活可以应对大部分的灾备情况,但是碰到大面积停电,或者自然灾害的时候,服务依然会中断。

对上面的两地三中心进行改造,在异地也部署前端入口节点和应用,在城市 1 停止服务后将流量切到城市 2,可以在降低用户体验的情况下,进行降级。但用户的体验下降程度非常大。

所以大多数的互联网公司采用了异地双活的方案

图 3:简单的异地双活示意图

上图是一个简单的异地双活的示意图。流量经过 LB 后分发到两个城市的服务器集群中,服务器集群只连接本地的数据库集群,只有当本地的所有数据库集群均不能访问,才 failover 到异地的数据库集群中。

在这种方式下,由于异地网络问题,双向同步需要花费更多的时间。更长的同步时间将会导致更加严重的吞吐量下降,或者出现数据冲突的情况。

吞吐量和冲突是两个对立的问题,你需要在其中进行权衡。例如,为了解决冲突,引入分布式锁/分布式事务。

为了解决达到更高的吞吐量,利用中间状态、错误重试等手段,达到最终一致性;降低冲突,将数据进行恰当的 sharding,尽可能在一个节点中完成整个事务。

 对于一些无法接受最终一致性的业务,饿了么采用的是下图的方式:

 

对于个别一致性要求很高的应用,我们提供了一种强一致的方案(Global Zone),Globa Zone 是一种跨机房的读写分离机制,所有的写操作被定向到一个 Master 机房进行,以保证一致性,读操作可以在每个机房的 Slave 库执行,也可以 bind 到 Master 机房进行,这一切都基于我们的数据库访问层(DAL)完成,业务基本无感知。

        《饿了么异地多活技术实现(一)总体介绍》

也就是说,在这个区域是不能进行双活的。采用主从而不是双写,自然解决了冲突的问题。

实际上,异地双活和异地多活已经很像了,双活的结构更为简单,所以在程序架构上不用做过多的考虑,只需要做传统的限流,failover 等操作即可。

但其实双活只是一个临时的步骤,最终的目的是切换到多活。因为双活除了有数据冲突上的问题意外,还无法进行横向扩展。

2.5、异地多活

RDS是关系型数据库服务(Relational Database Service)的简称,是一种即开即用、稳定可靠、可弹性伸缩的在线数据库服务。

图 4:异地多活的示意图

根据异地双活的思路,我们可以画出异地多活的一种示意图。每个节点的出度和入度都是 4,在这种情况下,任何节点下线都不会对业务有影响。

但是,考虑到距离的问题,一次写操作将带来更大的时间开销。时间开销除了影响用户体验以外,还带来了更多的数据冲突。

在严重的数据冲突下,使用分布式锁的代价也更大。这将导致系统的复杂度上升,吞吐量下降。所以上图的方案是无法使用的。

回忆一下我们在解决网状网络拓扑的时候是怎么优化的?引入中间节点,将网状改为星状:

图 5:星状的异地多活

改造为上图后,每个城市下线都不会对数据造成影响。对于原有请求城市的流量,会被重新 LoadBalance 到新的节点(最好是 LB 到最近的城市)。

为了解决数据安全的问题,我们只需要针对中心节点进行处理即可。但是这样,对于中心城市的要求,比其他城市会更高。

比如恢复速度,备份完整性等,这里暂时不展开。我们先假定中心是完全安全的。

如果我们已经将异地多活的业务部署为上图的结构,很大程度解决了数据到处同步的问题,不过依然会存在大量的冲突,冲突的情况可以简单认为和双活差不多。那么还有没有更好的方式呢?

回顾一下前文提到的饿了么的 GlobalZone 方案,总体思路就是“去分布式”,也就是说将写的业务放到一个节点的(同城)机器上。所以,别一味的分布式。

阿里的解决方案

阿里理想中的异地多活架构

实际上我猜测很多业务也是按照上图去实现的,比如滴滴打车业务这种,所有的业务都是按城市划分开的。

用户、车主、目的地,他们的经纬度通常都是在同一个城市的,这个我在之前“MySQL分库分表”的文章里面也阐述过了。单个数据中心并不需要和其他数据中心进行数据交互,只有在统计出报表的时候才需要,但报表是不太注重实时性的。 

那么,在这种情况下,全国的业务其实可以被很好的 sharding 的。但是对于电商这种复杂的场景和业务,按照前文说的方式进行 sharding 已经无法满足需求了。

因为业务线非常复杂,数据依赖也非常复杂,每个数据中心相互进行数据同步的情况无可避免。

淘宝的解决方式和我们切分微服务的方式有点类似:

淘宝按照单元切分的异地多活架构

注意看图中的数据同步箭头。以交易单元为例,属于交易单元的业务数据,将与中心单元进行双向同步;不属于交易单元的业务数据,单向从中心单元同步。

中心单元承担了最复杂的业务场景,业务单元承担了相对单一的场景。对于业务单元,可以进行弹性伸缩和容灾。

对于中心单元,扩展能力较差,稳定性要求更高。可以遇见,大部分的故障都会出现在中心单元。

按照业务进行单元切分,已经需要对代码和架构进行彻底的改造了(可能这也是为什么阿里要先从双活再切到多活,历时3年)。比如,业务拆分,依赖拆分,网状改星状,分布式事务,缓存失效等。

除了对于编码的要求很高以外,对测试和运维也有非常大的挑战。如此复杂的情况,如何进行自动化覆盖,如何进行演练,如何改造流水线。这种级别的灾备,不是一般公司敢做的,投入产出也不成正比。

不过还是可以把这种场景当作我们的“假想敌”,去思考我们自己的业务,未来会怎么发展,需要做到什么级别的灾备。相对而言,饿了么的多活方案可能更适合大多数的企业。

本文只是通过画图的方式进行了简单的描述,其实异地多活是需要很多很强大的基础能力的。

比如,数据传输,数据校验,数据操作层(简化客户端控制写和同步的过程)等。

 

最后,留几个问题大家可以思考一下:

  1. 服务按照异地多活方式部署,sharding key 根据省市区进行分片。假设用户在多个城市交汇的地方,那么如何处理才能让他拉到比较正常的数据?

  2. 你们现在的业务模块中,哪些业务是可以做多活的,哪些无法做多活?

  3. 所有的业务都要做多活吗?还是只需要核心业务做多活?

三、常见容错机制:failover、failfast、failback、failsafe

3.1、failover:失效转移

Fail-Over的含义为“失效转移”,是一种备份操作模式,当主要组件异常时,其功能转移到备份组件。其要点在于有主有备,且主故障时备可启用,并设置为主。如Mysql的双Master模式,当正在使用的Master出现故障时,可以拿备Master做主使用。

3.2、failfast:快速失败

从字面含义看就是“快速失败”,尽可能的发现系统中的错误,使系统能够按照事先设定好的错误的流程执行,对应的方式是“fault-tolerant(错误容忍)”。以JAVA集合(Collection)的快速失败为例,当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常(发现错误执行设定好的错误的流程),产生fail-fast事件。

3.3、failback:失效自动恢复

Fail-over之后的自动恢复,在簇网络系统(有两台或多台服务器互联的网络)中,由于要某台服务器进行维修,需要网络资源和服务暂时重定向到备用系统。在此之后将网络资源和服务器恢复为由原始主机提供的过程,称为自动恢复。

3.4、failsafe:失效安全

Fail-Safe的含义为“失效安全”,即使在故障的情况下也不会造成伤害或者尽量减少伤害。维基百科上一个形象的例子是红绿灯的“冲突监测模块”当监测到错误或者冲突的信号时会将十字路口的红绿灯变为闪烁错误模式,而不是全部显示为绿灯。

四、异地多活设计四大技巧 

4.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 中心登录是无法登录的这个怎么处理?

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

异地多活本质上是通过异地的数据冗余,来保证在极端异常的情况下业务也能够正常提供给用户。

数据冗余是要将数据从 A 地同步到 B 地,从业务的角度来看是越快越好,但不可能很快,因为这是物理定律决定的,几种方法可以参考:

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

这和我上一期讲到的同城异区架构类似,但搭建跨城异地的高速网络成本远远超过同城异区的高速网络,成本巨大,一般只有巨头公司才能承担

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

简单来说就是不重要的数据不同步,同步后没用的数据不同步,只同步核心业务相关的数据。

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

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

例如,A 机房注册了一个用户,业务上不要求能够在 50 毫秒内就同步到所有机房,正常情况下要求 5 分钟同步到所有机房即可,异常情况下甚至可以允许 1 小时或者 1 天后能够一致。

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

而对“用户信息”来说,5 分钟后同步也没有问题,也不需要采取其他措施来弥补,但还是会影响用户体验,即用户看到了旧的用户信息,这个问题怎么解决呢?

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

数据同步是异地多活架构设计的核心,幸运的是基本上存储系统本身都会有同步的功能。例如,MySQL 的主备复制、Redis 的 Cluster 功能、Elasticsearch 的集群功能。这些系统本身的同步功能已经比较强大,能够直接拿来就用,但这也无形中将我们引入了一个思维误区:只使用存储系统的同步功能!

既然说存储系统本身就有同步功能,而且同步功能还很强大,为何说只使用存储系统是一个思维误区呢?因为虽然绝大部分场景下,存储系统本身的同步功能基本上也够用了,但在某些比较极端的情况下,存储系统本身的同步功能可能难以满足业务需求

MySQL 为例,MySQL 5.1 版本的复制是单线程的复制,在网络抖动或者大量数据同步时,经常发生延迟较长的问题,短则延迟十几秒,长则可能达到十几分钟。而且即使我们通过监控的手段知道了 MySQL 同步时延较长,也难以采取什么措施,只能干等。

Redis 又是另外一个问题,Redis 3.0 之前没有 Cluster 功能,只有主从复制功能,而为了设计上的简单,Redis 2.8 之前的版本,主从复制有一个比较大的隐患:从机宕机或者和主机断开连接都需要重新连接主机,重新连接主机都会触发全量的主从复制。这时主机会生成内存快照,主机依然可以对外提供服务,但是作为读的从机,就无法提供对外服务了,如果数据量大,恢复的时间会相当长。

可以将多种手段配合存储系统的同步来使用,甚至可以不采用存储系统的同步方案,改用自己的同步方案。

还是以前面的“用户子系统”为例,我们可以采用如下几种方式同步数据:

(1)消息队列方式

对于账号数据,由于账号只会创建不会修改和删除(假设我们不提供删除功能),我们可以将账号数据通过消息队列同步到其他业务中心。

(2) 二次读取方式

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

(3) 存储系统同步方式

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

(4) 回源读取方式

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

(5) 重新生成数据方式

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

注意:以上方案仅仅是示意,实际的设计方案要比这个复杂一些,还有很多细节要考虑。

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

 
 

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

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

异地多活也无法保证 100% 的业务可用,这是由物理规律决定的,光速和网络的传播速度、硬盘的读写速度、极端异常情况的不可控等,都是无法 100% 解决的。所以针对这个思维误区,我的答案是“忍”!否则本来想为了保证最后的 0.01% 的用户的可用性,做一个完美方案,结果却发现 99.99% 的用户都保证不了了。

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

当然,针对银行转账这个业务,虽然无法做到“实时转账”的异地多活,但可以通过特殊的业务手段让转账业务也能实现异地多活。例如,转账业务除了“实时转账”外,还提供“转账申请”业务,即小明在上海业务中心提交转账请求,但上海的业务中心并不立即转账,而是记录这个转账请求,然后后台异步发起真正的转账操作,如果此时北京业务中心不可用,转账请求就可以继续等待重试;假设等待 2 个小时后北京业务中心恢复了,此时上海业务中心去请求转账,发现余额不够,这个转账请求就失败了。小明再登录上来就会看到转账申请失败,原因是“余额不足”。

不过需要注意的是“转账申请”的这种方式虽然有助于实现异地多活,但其实还是牺牲了用户体验的,对于小明来说,本来一次操作的事情,需要分为两次:一次提交转账申请,另外一次是要确认是否转账成功。

虽然我们无法做到 100% 可用性,但并不意味着我们什么都不能做,为了让用户心里更好受一些,我们可以采取一些措施进行安抚或者补偿,例如:

挂公告

说明现在有问题和基本的问题原因,如果不明确原因或者不方便说出原因,可以发布“技术哥哥正在紧急处理”这类比较轻松和有趣的公告。

事后对用户进行补偿

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

补充体验

对于为了做异地多活而带来的体验损失,可以想一些方法减少或者规避。以“转账申请”为例,为了让用户不用确认转账申请是否成功,我们可以在转账成功或者失败后直接给用户发个短信,告诉他转账结果,这样用户就不用时不时地登录系统来确认转账是否成功了。

核心思想

异地多活设计的理念可以总结为一句话:采用多种手段,保证绝大部分用户的核心业务异地多活!

附录:

《饿了么异地多活技术实现(一)总体介绍》

《饿了么框架工具部技术博客》

《阿里异地多活与同城双活的架构演进》

《阿里云 数据库异地多活解决方案》

《异地多活没那么难》

《分布式系统 - 关于异地多活的一点笔记 - overview》

《异地多活设计4大技巧》

posted @ 2021-02-15 17:59  杨兮臣  阅读(572)  评论(0编辑  收藏  举报