本课时我们来学习多可用区容灾、多活、两地三中心的高可用架构设计。

学前知识

首先我们来了解一些基础概念:

  • 地域,它通常是我们在进行 IDC 规划,业务覆盖的用户范围,以及评估网络质量时需要重点考虑的概念。地域以城市为最小单元命名,如:北京、天津等 。
  • 可用区,可以理解为独立机房 IDC,独立的可用区是需要完全具备隔离性的,如风火水电这些基础设施、网络一定要进行物理上的隔离,这样才能保障独立的可用区能够在为业务多活架构提供可靠基础设施保障。

对于多个可用区的设计,由于业务间访问延迟时间上有硬性要求,所以建议两个可用区的选址在保障独立物理环境前提下,举例越近越好。通常同城多可用之间的一个物理距离通常是在 100 公里之内,这样尽量让互访延迟在 2ms 以内。

接下来我们讲一下对于可用区高可用设计模式,通常有如下模式:

  • 可用区容灾,可用区容灾是指两个以上的可用区节点,通常是以主备形式存在的,备可用区在正常情况是不对外提供服务的,只在主可用区出现故障以后起到容灾切换的作用。
  • 同城多活,它是指同地域多个可用区能够同时服务。这些可用区是要同时对外提供服务的。一个可用区即使出现了故障,其他的可用区也能够整体可用,不影响整体的用户访问,这就是同城多活的结构。
  • 两地三中心,它是指在同城双活数据中心的基础上,增加了一个异地灾备数据中心。

了解了这些基础概念以后,我们再来讲一下,在灾备和同城多活这种可用区设计方案的时候,我们通常需要关注的一些单元和模块。

高可用架构 两地三中心 两地三中心网络架构_运维

如上图所示,包含了入口层、逻辑层、数据层和基建,入口层主要包含了代理网关和负载均衡;而逻辑层主要是和代码服务相关的内容;数据层主要用于存取数据或文本等相关服务,而基建层是指物理设施和网络设备,都是在进行可用区的高可用方案的时候,需要重点设计的。

在这张图的底部会看到公共组件这一层,这里我罗列了两个服务,一个是 DNS 服务,另外一个是K8s 服务,K8s 作为一个整体 PaaS 平台来提供调度, DNS 主要是提供域名的解析。

回到图中,我们来讲一讲在作高可用设计时候,每一层通常重点需要考虑:

基建层的高可用设计,主要要求是需要独立的基础设施,机房节点之间的网络延迟也是需要重点评估。

逻辑层中我们可能需要重点关注的是应用的状态,尽可能地把这些需要有状态化的数据下放到数据层,逻辑层能够更好地及时进行弹性扩容,来支持容灾的架构。

对于公共组件层,则需要提供平台化的调度支持,比如 K8s,需要支持多可用区的调度,以及 DevOps 流程打通。

入口层里,如 DNS,可能需要从 DNS 解析这一层考虑如何进行流量分配,以及出现故障以后如何进行快速调度策略。

数据层则要求数据一致性和实时性,这通常是在数据库在做多活方案时一个非常大的难题,也是需要企业去花很大的精力去投入的。本课时我们主要围绕公共组件层和数据层,结合入口层的设计方式给你进行介绍。

基建层-DNS 服务高可用设计

首先我们来讲一讲在基础层 DNS 服务高可用的设计模式。我们知道 DNS 在整个网站服务和当前技术架构里起到一个非常核心的作用,它能够提供域名的解析。那么对于 DNS 整个的高可用设计,我们可以分为两个方面进行介绍,一方面是围绕 DNS 服务本身的高可用设计,还有就是围绕 DNS 解析服务的高可用设计。

我们先来讲解 DNS 服务高可用的设计, DNS 协议本身是具备可靠性的,如:在客户端配置多个 DNS 服务地址或者有多个权威 DNS 的时候,DNS 协议在寻求解析过程中供容灾设计(1个节点无法解析,自动选择下一个DNS节点),可靠性比较高。

高可用架构 两地三中心 两地三中心网络架构_高可用架构 两地三中心_02

所以,DNS 服务本身的高可用大企业通常会把自己的权威 DNS 分多个地域并结合 DNS 主从的高可用架构模式,如图DNS服务节点部署到不同地域的AZ(可用区),一个地域 AZ 中的 DNS 出现问题以后,其他地域的权威 DNS 仍能够正常进行解析,后端启用一套配置和数据服务源,主要用作配置文件、DNS 数据文件的同步分发。

大企业 DNS 服务更加要求支撑海量并发及抵抗 DDOS 等恶意攻击抵御能力,则会结合一些全局性的负载均衡方案,如本套课程课时 34 介绍的 Anycast,使用 anycast + DNS 分地域部署,从入口层打散用户的流量请求,并且根据 Anycast 的协议,实现动态的融灾,增强整体可用性。

DNS 解析的高可用模式

除了 DNS 服务本身的高可用模式外,接下来再讲一讲 DNS 解析的高可用模式。

轮巡的解析模式

第一种需要介绍的就是 DNS 的解析模式也就是轮巡的解析模式,服务端给客户端同时返回多个 AZ记录的解析。这样的好处是可以降低提供访问服务端(RS1、RS2)的压力。

高可用架构 两地三中心 两地三中心网络架构_高可用架构 两地三中心_03

这种模式实现起来相对简单,我们只需要配置的同一个域名的多条 A 解析记录就可以实现。

缺点就是它是基于轮巡的模式来进解析,维度不能够做到更细致化,无法提供一个智能的,如:基于用户地域的流量解析模式。

智能 DNS

如果考虑解决这样的问题,我们可以考虑使用的第 2 套方案-智能 DNS,它会动态地判断访问者的来源,根据不同的访问者的来源的 IP 地址和来分来了解他具体的地域,同时返回给用户针对地域特定的 IP地址。

高可用架构 两地三中心 两地三中心网络架构_高可用架构 两地三中心_04

如在这张图里面,我们会看到一个在广州的用户,在请求 DNS 的时候,DNS 会判断用户所在的区域,如果在广州的话,就会返回用户我们网站在广州部署的真实节点服务IP,这个时候用户拿到的 IP 就是请求广州的 AZ 可用区的后台服务。

同样,在北京的用户去请求 DNS 之后,返回的是北京这边真实的后台服务 IP 地址,这样就可以把不同地域的用户就调度到离用户最近的一组 AZ 服务节点上去,这样对于服务端而言,就可以尽可能地打散用户的请求,降低后台服务压力。对客户端而言,这可以降低用户的延迟,提高网站的访问体验。

智能 DNS 的美中不足之处在于需要自建难度较大,且成本也需要更大的投入,所以对于小企业可能会更多地采用一些第三方服务或者是一些公有的服务。

结合DNS的高可用再来讲讲AZ故障时候切换原理,单个可用区(AZ1),如图中假设对外网站服务域名是 ,如果可用区 1(AZ1) 出现整体的故障,这个时候我就可以把这个域名解析成 2.2.2.2这个对外 IP 地址,用户就去请求 AZ2,这样就完成了通过 DNS 进行切换。

其实我们能遇到可用区 IDC 整个挂掉的可能性并不多,通常是一个可用区中内部有一部分服务出现问题,比如这张图里,假设内部中的 LB(负载均衡)调用我们的 DB(数据库),这里出现了问题,我们考虑通过 DNS 去做整体切换代价是比较大的,所以我们可以考虑需要在局部进行这样的切换,这时我们就可以通过 LB 切换到可用区 2(AZ2)中的 DB。

高可用架构 两地三中心 两地三中心网络架构_运维_05

高可用架构 两地三中心 两地三中心网络架构_运维_06

这种设计需要在底层网络把多个可用区的 IP 在网络层进行多可用区的分发,使得 LB 能够在多可用区中动态地通过 VIP 的方式飘移,这个是在底层网络以及 LB 的设计里面需要去考虑的。

另外这里切换的例子中,对于数据库考虑如何保障数据的一致性,不会有数据的丢失,对于数据库这一层里它的高可用应该如何去设计,接下来我们拿 MySQL 进行举例讲解。

数据层-MySQL 服务高可用设计

这里我给你再介绍一下 MySQL 的一个主从同步原理,我们看到这样的一张图:

高可用架构 两地三中心 两地三中心网络架构_架构_07

数据首先写入的是 MySQL 主库,主库除了把数据写入到库中,同时以 Binlog 方式记录日志。而从库只需要启动 IO 线程,IO 线程实现从主库里面取出 Binlog 日志,拿到本地以后,写到从库里面的 relay log,从库的另外一个 SQL 线程,SQL 线程是专门用来负责读取本地 relay log 的,并且在读取完以后会写入本地的数据库里。这样我们就可以看到 MySQL 的主从同步原理,就是通过 Binlog 的日志方式进行主从之间的数据同步。主库里面做了什么样的更改和写入操作,从库里通过 relay log 同时能够进行同步更改。

MySQL 灾备模式

MySQL 灾备模式也是基于这样数据同步机制应用在多AZ间,并作 MySQL 数据主从同步模式,我们来看这样一张图:

高可用架构 两地三中心 两地三中心网络架构_运维_08

AZ2 里 DB 是主库,那么在 AZ1 的数据库为从库。正常服务时数据往主 AZ2的数据库里面写入或者读取,从库(AZ1 的 DB) 只以 Binlog 的方式同步主库数据。

当 AZ2 出现问题以后,可以通过前端的负载均衡(LB)、数据库代理(Proxy)或者应用进行数据库的读写切换,我们将流量切换到 AZ1 的库作读取。

当可用区域AZ2重新恢复后,整个集群是需要重做主从的,需要重新建立主从模式,当然我们可以通过一些自动化的方式和一些开源工具来自动修复。

这是在灾备模式下面可以看到的原理,还是可以基于 Binlog 这样的数据同步机制方式,我们要尽可能地保障它的网络延迟更低(尽量在 1 到 2 毫秒的延迟范围)。

LB 高可用模式

如果要设计高可用的双活模式(两个可用区域都要同时对外提供服务),这个时候则要求两个 DB 之间要相互进行数据同步,也就是 AZ2 的数据要同步给 AZ1,AZ1 里面的 DB 发生数据更改之后要同步给 AZ2,所以这个时候我们需要考虑如何进行同步设计。

高可用架构 两地三中心 两地三中心网络架构_java_09

通常通过 MySQL 源生的 Binlog 方式是很难去实现的,就算实现起来也会有很大的问题(如:数据写入回环)。这时我们会考虑自己去研发一些工具来做,其中的原理我这里画了一张图:

高可用架构 两地三中心 两地三中心网络架构_高可用架构 两地三中心_10

这里有 MySQL1 和 MySQL2,假设两个 MySQL 在不同的可用区,那么在 MySQL1 里面,如果要写入数据的话,会在本地生成 Binlog。这个时候自研一个同步的进程( 如:Rsync SQL),它会去读取 MySQL1 里面的 Binlog 日志,并且把 Binlog 做反向解析,原始 Binlog 日志是二进制的,解析成一个 SQL 语句,再同步操作 MySQL2 。有了这样一层机制,就可以使得数据库数据发生更改时作到双向的同步。

自研这样一套程序的时候,实际上不仅要考虑 Binlog 的 SQL 解析,还需要考虑 AZ 的重复数据同步的问题,比如数据同步到 AZ1 以后,AZ1 可能又会同步到 AZ2 里面,这样就会造成回环重复写入。为了避免这样的问题,也需要在 Rsync SQL 这个自研进程里面考虑用一些解决方案(如设置标签等)解决重复同步的问题。