高可用解决方案:同城双活?异地双活?异地多活?怎么实现?

后台服务能够划分为两类,有状态和无状态。高可用对于无状态的应用来讲是比较简单的,无状态的应用,只须要经过F5或者任何代理的方式就能够很好的解决。后文描述的主要是针对有状态的服务进行分析。服务端进行状态维护主要是经过磁盘或内存进行保存,好比MySQL数据库,redis等内存数据库。除了这两种类型的维护方式,还有jvm的内存的状态维持,但jvm的状态生命周期一般很短。前端

高可用的一些解决方案

高可用,从发展来看,大体通过了这几个过程:mysql

  • 冷备
  • 双机热备
  • 同城双活
  • 异地双活
  • 异地多活

在聊异地多活的时候,仍是先看一些其余的方案,这有利于咱们理解不少设计的原因。linux

冷备redis

冷备,经过中止数据库对外服务的能力,经过文件拷贝的方式将数据快速进行备份归档的操做方式。简而言之,冷备,就是复制粘贴,在linux上经过cp命令就能够很快完成。能够经过人为操做,或者定时脚本进行。有以下好处:sql

  • 简单
  • 快速备份(相对于其余备份方式)
  • 快速恢复。只须要将备份文件拷贝回工做目录即完成恢复过程(亦或者修改数据库的配置,直接将备份的目录修改成数据库工做目录)。更甚,经过两次mv命令就可瞬间完成恢复。
  • 能够按照时间点恢复。好比,几天前发生的拼多多优惠券漏洞被人刷掉不少钱,能够根据前一个时间点进行还原,“挽回损失”。

以上的好处,对于之前的软件来讲,是很好的方式。可是对于现现在的不少场景,已经很差用了,由于:数据库

  • 服务须要停机。n个9确定没法作到了。而后,之前咱们的停机冷备是在凌晨没有人使用的时候进行,可是如今不少的互联网应用已是面向全球了,因此,任什么时候候都是有人在使用的。
  • 数据丢失。若是不采起措施,那么在完成了数据恢复后,备份时间点到还原时间内的数据会丢失。传统的作法,是冷备还原之后,经过数据库日志手动恢复数据。好比经过redo日志,更甚者,我还曾经经过业务日志去手动回放请求恢复数据。恢复是极大的体力活,错误率高,恢复时间长。
  • 冷备是全量备份。全量备份会形成磁盘空间浪费,以及容量不足的问题,只能经过将备份拷贝到其余移动设备上解决。因此,整个备份过程的时间其实更长了。想象一下天天拷贝几个T的数据到移动硬盘上,须要多少移动硬盘和时间。而且,全量备份是没法定制化的,好比只备份某一些表,是没法作到的。

如何权衡冷备的利弊,是每一个业务须要考虑的。缓存

双机热备安全

热备,和冷备比起来,主要的差异是不用停机,一边备份一边提供服务。但还原的时候仍是须要停机的。因为咱们讨论的是和存储相关的,因此不将共享磁盘的方式看做双机热备。服务器

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等等。

同城双活

前面讲到的几种方案,基本都是在一个局域网内进行的。业务发展到后面,有了同城多活的方案。和前面比起来,不信任的粒度从机器转为了机房。这种方案能够解决某个IDC机房总体挂掉的状况(停电,断网等)。

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

在程序代码的辅助下,有的业务还能够作到真正的双活,即同一个业务,双主,同时提供读写,只要处理好冲突的问题便可。须要注意的是,并非全部的业务都能作到。

业界更多采用的是两地三中心的作法。远端的备份机房能更大的提供灾备能力,能更好的抵抗地震,恐袭等状况。双活的机器必须部署到同城,距离更远的城市做为灾备机房。灾备机房是不对外提供服务的,只做为备份使用,发生故障了才切流量到灾备机房;或者是只做为数据备份。缘由主要在于:距离太远,网络延迟太大。如上图,用户流量经过负载均衡,将服务A的流量发送到IDC1,服务器集A;将服务B的流量发送到IDC2,服务器B;同时,服务器集a和b分别从A和B进行同城专线的数据同步,而且经过长距离的异地专线往IDC3进行同步。当任何一个IDC当机时,将全部流量切到同城的另外一个IDC机房,完成了failover。当城市1发生大面积故障时,好比发生地震致使IDC1和2同时中止工做,则数据在IDC3得以保全。同时,若是负载均衡仍然有效,也能够将流量所有转发到IDC3中。不过,此时IDC3机房的距离很是远,网络延迟变得很严重,一般用户的体验的会受到严重影响的。上图是一种基于Master-Slave模式的两地三中心示意图。城市1中的两个机房做为1主1从,异地机房做为从。也能够采用同城双主+keepalived+vip的方式,或者MHA的方式进行failover。但城市2不能(最好不要)被选择为Master。

异地双活

同城双活能够应对大部分的灾备状况,可是碰到大面积停电,或者天然灾害的时候,服务依然会中断。对上面的两地三中心进行改造,在异地也部署前端入口节点和应用,在城市1中止服务后将流量切到城市2,能够在下降用户体验的状况下,进行降级。但用户的体验降低程度很是大。

因此大多数的互联网公司采用了异地双活的方案。上图是一个简单的异地双活的示意图。流量通过LB后分发到两个城市的服务器集群中,服务器集群只链接本地的数据库集群,只有当本地的全部数据库集群均不能访问,才failover到异地的数据库集群中。

在这种方式下,因为异地网络问题,双向同步须要花费更多的时间。更长的同步时间将会致使更加严重的吞吐量降低,或者出现数据冲突的状况。吞吐量和冲突是两个对立的问题,你须要在其中进行权衡。例如,为了解决冲突,引入分布式锁/分布式事务;为了解决达到更高的吞吐量,利用中间状态、错误重试等手段,达到最终一致性;下降冲突,将数据进行恰当的sharding,尽量在一个节点中完成整个事务。

对于一些没法接受最终一致性的业务,饿了么采用的是下图的方式:对于个别一致性要求很高的应用,咱们提供了一种强一致的方案(Global Zone),Globa Zone是一种跨机房的读写分离机制,全部的写操做被定向到一个 Master 机房进行,以保证一致性,读操做能够在每一个机房的 Slave库执行,也能够 bind 到 Master 机房进行,这一切都基于咱们的数据库访问层(DAL)完成,业务基本无感知。

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

实际上,异地双活和异地多活已经很像了,双活的结构更为简单,因此在程序架构上不用作过多的考虑,只须要作传统的限流,failover等操做便可。但其实双活只是一个临时的步骤,最终的目的是切换到多活。由于双活除了有数据冲突上的问题意外,还没法进行横向扩展。

异地多活根据异地双活的思路,咱们能够画出异地多活的一种示意图。每一个节点的出度和入度都是4,在这种状况下,任何节点下线都不会对业务有影响。可是,考虑到距离的问题,一次写操做将带来更大的时间开销。时间开销除了影响用户体验之外,还带来了更多的数据冲突。在严重的数据冲突下,使用分布式锁的代价也更大。这将致使系统的复杂度上升,吞吐量降低。因此上图的方案是没法使用的。

回忆一下咱们在解决网状网络拓扑的时候是怎么优化的?引入中间节点,将网状改成星状:改造为上图后,每一个城市下线都不会对数据形成影响。对于原有请求城市的流量,会被从新LoadBalance到新的节点(最好是LB到最近的城市)。为了解决数据安全的问题,咱们只须要针对中心节点进行处理便可。可是这样,对于中心城市的要求,比其余城市会更高。好比恢复速度,备份完整性等,这里暂时不展开。咱们先假定中心是彻底安全的。

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

回顾一下前文提到的饿了么的GlobalZone方案,整体思路就是“去分布式”,也就是说将写的业务放到一个节点的(同城)机器上。阿里是这么思考的:实际上我猜想不少业务也是按照上图去实现的,好比滴滴打车业务这种,全部的业务都是按城市划分开的。用户、车主、目的地,他们的经纬度一般都是在同一个城市的。单个数据中心并不须要和其余数据中心进行数据交互,只有在统计出报表的时候才须要,但报表是不太注重实时性的。那么,在这种状况下,全国的业务其实能够被很好的sharding的。

可是对于电商这种复杂的场景和业务,按照前文说的方式进行sharding已经没法知足需求了。由于业务线很是复杂,数据依赖也很是复杂,每一个数据中心相互进行数据同步的状况无可避免。淘宝的解决方式和咱们切分微服务的方式有点相似:注意看图中的数据同步箭头。以交易单元为例,属于交易单元的业务数据,将与中心单元进行双向同步;不属于交易单元的业务数据,单向从中心单元同步。中心单元承担了最复杂的业务场景,业务单元承担了相对单一的场景。对于业务单元,能够进行弹性伸缩和容灾;对于中心单元,扩展能力较差,稳定性要求更高。能够碰见,大部分的故障都会出如今中心单元。

按照业务进行单元切分,已经须要对代码和架构进行完全的改造了(可能这也是为何阿里要先从双活再切到多活,历时3年)。好比,业务拆分,依赖拆分,网状改星状,分布式事务,缓存失效等。除了对于编码的要求很高之外,对测试和运维也有很是大的挑战。如此复杂的状况,如何进行自动化覆盖,如何进行演练,如何改造流水线。这种级别的灾备,不是通常公司敢作的,投入产出也不成正比。不过仍是能够把这种场景看成咱们的“假想敌”,去思考咱们本身的业务,将来会怎么发展,须要作到什么级别的灾备。相对而言,饿了么的多活方案可能更适合大多数的企业。

本文只是经过画图的方式进行了简单的描述,其实异地多活是须要不少很强大的基础能力的。好比,数据传输,数据校验,数据操做层(简化客户端控制写和同步的过程)等。

来源 | https://blog.dogchao.cn/?p=299
image
相关文章
相关标签/搜索