【实战场景】服务部署之双活的那些思考

在这里插入图片描述

开篇词:

1.冗余设计

谈异地双活前,不得不提开发中常用的冗余设计,冗余设计是保证系统和数据高可用的最常的手段。

  • 对于服务来说,冗余的思想就是相同的服务部署多份,如果正在使用的服务突然挂掉的话,系统可以很快切换到备份服务上,大大减少系统的不可用时间,提高系统的可用性。

  • 对于数据来说,冗余的思想就是相同的数据备份多份,这样就可以很简单地提高数据的安全性。

2.异地多活

异地多活是冗余思想在高可用系统设计中最典型的应用之一。

  • 异地多活 : 将服务部署在异地的不同机房中,并且,它们可以同时对外提供服务。

  • 和传统的灾备设计相比,异地多活最明显的改变在于“多活”,即所有站点都是同时在对外提供服务的。

  • 异地多活是为了应对突发状况比如火灾、地震等自然或者人为灾害。

3.故障转移

所谓故障转移,简单来说就是实现不可用服务快速且自动地切换到可用服务,整个过程不需要人为干涉。

这些故障一般体现在 3 个方面:

  • 硬件故障:CPU、内存、磁盘、网卡、交换机、路由器
  • 软件问题:代码 Bug、版本迭代
  • 不可抗力:地震、水灾、火灾、战争

系统发生故障其实是不可避免的,尤其是规模越大的系统,发生问题的概率也越大,所以必须要配合上 故障转移 才可以!

在这里插入图片描述

干货篇:

1. 系统可用性

一个好的软件架构应该遵循以下 3 个原则:

  • 高性能:意味着系统拥有更大流量的处理能力,更低的响应延迟
  • 高可用
  • 易扩展:系统在迭代新功能时,能以最小的代价去扩展,系统遇到流量压力时,可以在不改动代码的前提下,去扩容系统
    其中,高性能意味着系统拥有更大流量的处理能力,更低的响应延迟。

「高可用」这个概念,通常用 2 个指标来衡量:

  • 平均故障间隔 MTBF(Mean Time Between Failure):表示两次故障的间隔时间,也就是系统「正常运行」的平均时间,这个时间越长,说明系统稳定性越高
  • 故障恢复时间 MTTR(Mean Time To Repair):表示系统发生故障后「恢复的时间」,这个值越小,故障对用户的影响越小

可用性与这两者的关系:

可用性(Availability)= MTBF / (MTBF + MTTR) * 100%

这个公式得出的结果是一个「比例」,通常我们会用「N 个 9」来描述一个系统的可用性。

在这里插入图片描述

从这张图你可以看到,要想达到 4 个 9 以上的可用性,平均每天故障时间必须控制在 10 秒以内。

也就是说,只有故障的时间「越短」,整个系统的可用性才会越高,每提升 1 个 9,都会对系统提出更高的要求。

2. 历史架构的演进

(1).单体架构:

客户端请求进来,业务应用读写数据库,返回结果,非常好理解。

缺点:

  • 一旦遭遇意外,例如磁盘损坏、操作系统异常、误删数据,那这意味着所有数据就全部「丢失」了,这个损失是巨大的。
(2).单体架构+数据库定时备份:

你可以对数据做备份,把数据库文件「定期」cp 到另一台机器上,这样,即使原机器丢失数据,你依旧可以通过备份把数据「恢复」回来,以此保证数据安全。

缺点:

  • 恢复需要时间:业务需先停机,再恢复数据,停机时间取决于恢复的速度,恢复期间服务「不可用」
  • 数据不完整:因为是定期备份,数据肯定不是「最新」的,数据完整程度取决于备份的周期
(3).主从副本:

在另一台机器上,再部署一个数据库实例,让这个新实例成为原实例的「副本」,让两者保持「实时同步」
优点:

  • 数据完整性高:主从副本实时同步,数据「差异」很小
  • 抗故障能力提升:主库有任何异常,从库可随时「切换」为主库,继续提供服务
  • 读性能提升:业务应用可直接读从库,分担主库「压力」读压力

缺点:

  • 风险不可控,如果恰好连接这个机柜的交换机 / 路由器发生故障,那么你的应用依旧有「不可用」的风险。
  • 虽然交换机 / 路由器也做了路线冗余,但不能保证一定不出问题。
(4).同城冷备:

A 机房的数据,定时在 B 机房做备份(拷贝数据文件),这样即使整个 A 机房遭到严重的损坏,B 机房的数据不会丢,通过备份可以把数据「恢复」回来,重启服务。这种方案,我们称之为「冷备」。为什么叫冷备呢?因为 B 机房只做备份,不提供实时服务,它是冷的,只会在 A 机房故障时才会启用。

缺点:

  • 数据不完整、恢复数据期间业务不可用,整个系统的可用性还是无法得到保证。
(5).同城热备:

热的意思是指,B 机房处于「待命」状态,A 故障后 B 可以随时「接管」流量,继续提供服务。
热备相比于冷备最大的优点是:

  • 随时可切换。
(6).同城双活:

虽然我们有了应对机房故障的解决方案,但这里有个问题是我们不能忽视的:A 机房挂掉,全部流量切到 B 机房,B 机房能否真的如我们所愿,正常提供服务?
我们的架构也是如此,此时的 B 机房虽然是随时「待命」状态,但 A 机房真的发生故障,我们要把全部流量切到 B 机房,其实是不敢百分百保证它可以「如期」工作的。

B 机房实时接入了流量,还能应对随时的故障切换,这种方案我们把它叫做「同城双活」。

因为两个机房都能处理业务请求,这对我们系统的内部维护、改造、升级提供了更多的可实施空间(流量随时切换),现在,整个系统的弹性也变大了

缺点:

  • 虽然我们把 2 个机房当做一个整体来规划,但这 2 个机房在物理层面上,还是处于「一个城市」内,如果是整个城市发生自然灾害,例如地震、水灾(河南水灾刚过去不久),那 2 个机房依旧存在「全局覆没」的风险。
(7). 两地三中心:

按照前面的思路,把 C 机房用起来,最简单粗暴的方案还就是做「冷备」,即定时把 A、B 机房的数据,在 C 机房做备份,防止数据丢失。

两地是指 2 个城市,三中心是指有 3 个机房,其中 2 个机房在同一个城市,并且同时提供服务,第 3 个机房部署在异地,只做数据灾备。

缺点:

  • 这种架构方案,通常用在银行、金融、政企相关的项目中。它的问题还是前面所说的,启用灾备机房需要时间,而且启用后的服务,不确定能否如期工作。
(8).伪异地双活:

我们不再把 A、B 机房部署在同一个城市,而是分开部署,例如 A 机房放在北京,B 机房放在上海。

此时两个机房都接入流量,那上海机房的请求,可能要去读写北京机房的存储,

这里存在一个很大的问题:

  • 网络延迟。

  • 不止是延迟,远距离的网络专线质量,是远远达不到机房内网络质量的,专线网络经常会发生延迟、丢包、甚至中断的情况。总之,不能过度信任和依赖「跨城专线」。

在这里插入图片描述
在这里插入图片描述

3. 真正的异地双活

规避这个延迟问题。也就是说,上海机房的应用,不能再「跨机房」去读写北京机房的存储,只允许读写上海本地的存储,实现「就近访问」.

此时,你就必须在「存储层」做改造了,至此迎来了真正的异地双活

要想上海机房读写本机房的存储,那上海机房的存储不能再是北京机房的从库,而是也要变为「主库」。

因为只有两个机房都拥有「全量数据」,才能支持任意切换机房,持续提供服务。

[-----怎么实现这种「双主」架构呢?它们之间如何互相同步数据?------]

那就得借助中间件了,MySQL 本身就提供了双主架构,它支持双向复制数据

此外,除了数据库这种有状态的软件之外,你的项目通常还会使用到消息队列,例如 RabbitMQ、Kafka,这些也是有状态的服务,所以它们也需要开发双向同步的中间件,支持任意机房写入数据,同步至另一个机房。

看到了么,这一下子复杂度就上来了,单单针对每个数据库、队列开发同步中间件,就需要投入很大精力了。

业界也开源出了很多数据同步中间件,例如阿里的 Canal、RedisShake、MongoShake,可分别在两个机房同步 MySQL、Redis、MongoDB 数据。

现在,整个架构就变成了这样:

在这里插入图片描述

4. 异地双活的注意事项

但这里还会遇到一个问题,在很短的时间内,同一个用户修改同一条数据,两个机房无法确认谁先谁后,数据发生「冲突」。

这是一个很严重的问题,系统发生故障并不可怕,可怕的是数据发生「错误」,因为修正数据的成本太高了。我们一定要避免这种情况的发生。解决这个问题,有 2 个方案。

(1).第一个方案,数据同步中间件要有自动「合并」数据、解决「冲突」的能力。

这个方案实现起来比较复杂,要想合并数据,就必须要区分出「先后」顺序。我们很容易想到的方案,就是以「时间」为标尺,以「后到达」的请求为准。

但这种方案需要两个机房的「时钟」严格保持一致才行,否则很容易出现问题。

(2).第二个方案,从「源头」就避免数据冲突的发生。

从源头避免数据冲突的思路是:在最上层接入流量时,就不要让冲突的情况发生。

具体来讲就是,要在最上层就把用户「区分」开,部分用户请求固定打到北京机房,其它用户请求固定打到上海 机房,进入某个机房的用户请求,之后的所有业务操作,都在这一个机房内完成,从根源上避免「跨机房」。

所以这时,你需要在接入层之上,再部署一个「路由层」(通常部署在云服务器上),自己可以配置路由规则,把用户「分流」到不同的机房内。

但这个路由规则,具体怎么定呢?有很多种实现方式,最常见的 3 类:

a、按业务类型分片

这种方案是指,按应用的「业务类型」来划分。

举例:假设我们一共有 4 个应用,北京和上海机房都部署这些应用。但应用 1、2 只在北京机房接入流量,在上海机房只是热备。应用 3、4 只在上海机房接入流量,在北京机房是热备。

这样一来,应用 1、2 的所有业务请求,只读写北京机房存储,应用 3、4 的所有请求,只会读写上海机房存储。

这样按业务类型分片,也可以避免同一个用户修改同一条数据。

b、直接哈希分片

这种方案就是,最上层的路由层,会根据用户 ID 计算「哈希」取模,然后从路由表中找到对应的机房,之后把请求转发到指定机房内。

c、按地理位置分片

这种方案,非常适合与地理位置密切相关的业务,例如打车、外卖服务就非常适合这种方案。

拿外卖服务举例,你要点外卖肯定是「就近」点餐,整个业务范围相关的有商家、用户、骑手,它们都是在相同的地理位置内的。

针对这种特征,就可以在最上层,按用户的「地理位置」来做分片,分散到不同的机房。

双活的重点,是要优先保证「核心」业务先实现双活,并不是「全部」业务实现双活。

至此,我们才算实现了真正的「异地双活」!

在这里插入图片描述

总结

好了,总结一下这篇文章的重点。

1、一个好的软件架构,应该遵循高性能、高可用、易扩展 3 大原则,其中「高可用」在系统规模变得越来越大时,变得尤为重要

2、系统发生故障并不可怕,能以「最快」的速度恢复,才是高可用追求的目标,异地多活是实现高可用的有效手段

3、提升高可用的核心是「冗余」,备份、主从副本、同城灾备、同城双活、两地三中心、异地双活,异地多活都是在做冗余

4、同城灾备分为「冷备」和「热备」,冷备只备份数据,不提供服务,热备实时同步数据,并做好随时切换的准备

5、同城双活比灾备的优势在于,两个机房都可以接入「读写」流量,提高可用性的同时,还提升了系统性能。虽然物理上是两个机房,但「逻辑」上还是当做一个机房来用

6、两地三中心是在同城双活的基础上,额外部署一个异地机房做「灾备」,用来抵御「城市」级别的灾害,但启用灾备机房需要时间

7、异地双活才是抵御「城市」级别灾害的更好方案,两个机房同时提供服务,故障随时可切换,可用性高。但实现也最复杂,理解了异地双活,才能彻底理解异地多活

在这里插入图片描述

我是杰叔叔,一名沪漂的码农,下期再会!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值