关于后端:深入了解异地多活

3次阅读

共计 4419 个字符,预计需要花费 12 分钟才能阅读完成。

博客:cbb777.fun

全平台账号: 安妮的心动录

github: https://github.com/anneheartrecord

下文中我说的可能对,也可能不对,鉴于笔者程度无限,请君自辨。有问题欢送大家找我探讨~

零碎性能三指标

要想了解异地多活,咱们须要从架构设计的准则说起
现如今,咱们开发一个软件系统,对其要求越来越高,一个好的软件架构应该遵循以下 3 个准则:

  1. 高性能
  2. 高可用
  3. 易扩大
  • 高性能:零碎领有更大流量的解决能力,同时接口返回的速度应该尽可能的快。
  • 易扩大:零碎在迭代新性能的时候,可能以最小的代价去扩大,零碎遇到流量压力的时候,能够在不改变代码的前提上来扩容零碎。
  • 高可用:通常由两个指标来掂量,别离是均匀故障工夫和故障复原工夫

不同的软件,不同阶段的公司,产品开发的不同阶段,对这些指标的要求是不一样的:比方一个初创公司,这个时候用户、流量最重要,开发性能,让页面尽可能好看,做产品比其余指标更重要;当流量上来了之后,怎么尽可能缩短响应工夫,让零碎能解决的 QPS 更大,就成了至关重要的问题;当产品应用的人数足够多,影响力足够大,可用性的重要就凸现进去了,怎么保证系统尽可能稳固,不出问题,对于公司来说才是最重要的。
零碎产生故障是不可避免的,尤其是规模越大的零碎,相互之间的调用也更加简单,对于硬件的要求也越高,从实践上来说产生问题的概率也越大。这些故障个别提当初 3 个方面:

  1. 硬件故障:CPU 内存 磁盘 网卡 交换机 路由器
  2. 软件问题:代码 BUG 版本迭代 线上故障等等
  3. 不可抗力:地震 旱灾 火灾 和平

咱们通常用 N 个 9 来示意零碎的可用性高不高,从数据上能看进去,越到前面零碎可用性带来的均匀受害是越小的,然而难度是指数级别回升的。咱们平时写的小玩具和企业级的利用差异也无非是这几个方面:高并发、高性能、高可用。
这些危险随时都有可能产生,所以在面对故障的时候,零碎是否以【最快】的速度复原,就成了可用性的要害。
如何做到疾速复原呢?
异地多活 就是为了解决这个问题,而提出的高效解决方案

单机房

单机

客户端申请先进来,业务利用读写数据库,返回后果
这里的数据库是单机部署的,所以有一个致命的毛病:一旦遭逢意外,例如磁盘损坏、操作系统异样、误删数据,这意味着所有数据就全副【失落】了,这个损失是微小的

备份

咱们能够对数据做备份,将数据库文件【定期】copy 到另一台机器上,这样即便原机器失落数据,仍旧能够通过备份把数据【复原】回来,以此保障数据安全
这个计划施行起来尽管比较简单,但存在两个问题

  1. 复原须要工夫:业务须要先停机,在复原数据,这段时间服务是不可用的,对于一个零碎来说这显然不能忍耐
  2. 数据不残缺:因为是定期备份,数据必定不是最新的,会有丢数据的危险。这里补充一句,其实古代零碎想要做到数据实时强一致性,简直是不可能的

主从

能够在另一台机器上,再部署一个数据库实例,成为这个原实例的正本,让两者放弃【实时同步】,这里的实时同步要打上引号,因为两台机器有网络隔离,永远不可能真正的实时同步,比方当主库写一条数据,还没同步的时候就宕机了,这个时候从库就会有丢数据的可能。
咱们个别把原实例称为主库(master),新实例称作从库(slave),这个计划的长处在于

  • 数据完整性高:主从正本实时同步,数据差别很小
  • 抗故障能力晋升:主库有任何异样,从库能够随时切换为主库,持续提供服务
  • 读性能提醒:从库能够间接用来读

主从 + 多机器

同样的,业务利用也也能够在其余机器部署一份,防止单点。因为业务利用通常是【无状态】的,这里的无状态很好了解,业务代码的逻辑局部(除去数据库的局部),在什么机器上都能跑,且不会对机器造成长久化的影响,不像数据库一样存储数据,所以间接部署即可,非常简单。

因为业务利用部署了多个,所以当初还须要一个接入层,来做申请的负载平衡,个别是用 nginx 或者是 lvs,这样当一台机器宕机之后,另一台机器也能够【接管】所有流量,继续提供服务。

进步可用性的核心思想

从这些计划能够看出,晋升可用性的要害思路就是:冗余
放心一个实例故障,那就部署多个实例;放心一个机器宕机,那就部署多台机器;放心一个数据库可能会崩而后丢数据,那就多整几个数据库;这种冗余的思维放在机房层面,就产生了同城灾备、同城双活等计划;放在城市层面,就产生了两地三核心、异地双活、异地多活等计划

以上说的计划还是有毛病的,因为利用尽管部署了多台机器,然而这些机器的散布状况,咱们并没有去深究。
而一个机房有很多服务器,这些服务器通常会散布在一个个【机柜】上,如果应用的机器刚好在一个机柜,还是存在危险。
如果恰好链接这个机柜的交换机 / 路由器产生故障,那么你的利用仍旧有【不可用】的危险

哪怕是在不同机柜上,依旧会有危险,因为它们始终还是属于一个机房。
机房的故障率从事实角度来剖析其实真的很低,建设一个机房的要求是很高的,地理位置、温湿度管制、备用电源等等。机房厂商会在各方面做好防护,但即便这样,还是有以下事变

  • 15 年支付宝因为光纤被挖断,5 小时无法访问支付宝
  • 21 年 b 站服务器着火,3 小时无法访问
  • 21 年富途证券服务器断电,2 小时无法访问

可见,哪怕机房级别的防护曾经做的足够好,但只有有概率呈现问题,那现实情况就有可能产生。尽管概率很小,但一旦产生,就会造成重大损失。
像前文所说的一样,不同体量的零碎,关注的重点是不一样的。小零碎关注的重点是用户,这个阶段用户的规模、增长就是所有。在用户体量上来之后,会重点关注性能,优化接口响应工夫,接口打开速度等等。这个阶段更多的是关注用户体验,而体量再大上来,可用性就会变得尤为重要。像微信、支付宝这种全民级别的利用,如果机房产生一次故障,那么影响和损失都是微小的
咱们该如何应答机房级别的故障呢?没错,还是冗余

多机房

同城灾备

简略起见,能够在同一个城市再搭建一个机房,原机房为 A,新机房为 B,这两个机房的网络用一条【专线】连通。

为了防止 A 机房故障导致数据失落,所以咱们须要把数据在 B 机房也做【定时备份】。这种计划,咱们成为【冷备】。因为 B 机房只做备份,不提供服务,只有在 A 机房故障的时候才会弃用。
或者能够把 AB 之间的关系换成主从的关系,这样不仅能进步零碎吞吐量,也可能更加保证数据的完整性

在这个计划的构想中,如果 A 机房真挂掉了,要想保障服务不中断,还须要做这些事件

  1. B 机房所有从库升级成主库
  2. 在 B 机房部署利用,启动服务
  3. 部署接入层,配置转发规定
  4. DNS 指向 B 机房接入层,接入流量,业务复原

整个过程的每一步须要人为染指,且须要破费大量工夫,回复之前整个服务还是不可用的,如果想要做到故障之后立刻【切换】,就须要思考上面这种架构

这样的话,A 机房整个挂掉,咱们只须要做两件事

  1. B 机房所有从库晋升为主库
  2. DNS 指向 B 机房接入层,接入流量,业务回复

这种计划咱们叫【热备】,热备相比于冷备的最大长处是随时可切换,不同点有须要多加一层应用层和接入层,同时数据库层面的定时备份变成了实时备份,这些都是须要额定开销的。咱们把这两个计划统称为:同城灾备

同城灾备的最大劣势在于,咱们不必放心【机房】级别的故障了,一个机房产生危险,咱们只须要把流量切换到另一个机房,当然这不肯定会没有问题,比方冷备的问题是之前的备用系统没有通过流量的测试,不肯定能扛得住;热备也是,瘫了一个主零碎,那么备用系统的压力范畴,也不肯定能抗住。

同城双活

尽管有了应答机房故障的解决方案,然而有个问题是不能疏忽的:A 机房挂掉,全副流量切到 B 机房,B 机房是否真的能如咱们所愿,失常提供服务?
另外从老本的角度上看,咱们新部署一个机房,须要购买很多硬件资源,破费老本也是十分昂扬的,如果只是放在那里不去应用,是很浪费资源的一种体现。
因而咱们须要让 B 机房也接入流量,实时提供服务
只须要把 B 机房的接入层 IP 地址,退出到 dns 服务中,这样 B 机房从下层就能够有流量进来了

这里有一个新问题:B 机房的存储都是从库,而从库默认都是不可写的,也就是说 B 机房是解决不了写申请的。这个问题就应该在业务应用层解决,须要辨别读写拆散,个别是通过中间件实现,写流量给 A 机房,读流量能够给两个机房
这种架构有什么问题呢?

两地三核心

因为把两个机房当成一个整体来布局,如果是一个城市的话,当整个城市产生自然灾害的时候,例如地震、旱灾,那么仍旧可能有【全局覆没】的危险
这个时候就能够将备份机房放在另一个城市
两地三核心就是指两个城市,三个机房,其中 2 个机房在同一个城市,并且同时提供服务,第三个机房部署在异地,制作数据灾备。
这种架构计划,通常用在银行、金融、政企相干的我的项目中,问题还是启用后的服务,不确定是否如期工作。
所以想要真正抵挡城市级别的故障,越来越多的互联网公司,开始施行【异地双活】

异地双活

次要问题是跨机房的提早调用,当 B 地的利用去跨区域读写 A 地的存储,网络提早就会让整个申请变得十分慢。而要解决这个问题,就必须在存储层做革新了。
B 机房的存储不再是从库,而也要变为主库,同时两个机房的数据还要【相互同步】,无论客户端写哪一个机房,都要把数据同步到另一个机房。因为只有两个机房都领有全量数据,能力反对任意切换机房,继续提供服务。MySQL 自身是提供了双主架构的,反对双向数据复制,但平时用的不多。而且 Redis、mongoDB 等数据库是没有这个性能的,所以必须开发对应的【数据同步中间件】来实现双向同步的性能。
除了数据库这种有状态的软件之外,通常还会用到音讯队列,例如 rabbitMQ,kafka 等,这些也是有状态的服务,所以它们也须要开发双向同步的中间件,反对任意机房写入数据,同步至另一个机房
业界开源出了很多数据同步中间件,例如阿里的 canal、redisshake、mongoshake,可别离在两个机房同步 MySQL、REDIS、MONGODB 数据
这样的话有一个新的问题,两个机房都能够写,如果操作的是同一条数据,就很容易产生竞态的问题
别离有两个计划

  1. 音讯同步中间件要有主动解决数据的能力,辨别出操作的先后顺序
  2. 从源头防止数据抵触的产生

个别都是采纳第二种计划:在最上层接入流量的时候,就不要让抵触的状况产生。
具体来讲就是将用户辨别开,局部用户申请固定达到北京机房,其余用户申请固定打到上海机房。进入某个机房的用户申请,之后的所有业务操作,都在这一个机房内实现,从本源上防止【跨机房】。
这时候须要在接入层之上,再部署一个路由层,本人配置路由规定,把用户分流到不同的机房内。
一般来说有三种形式

  • 按业务类型分片,比方某个子域的申请固定全打在某个机房
  • 间接哈希分片,先对申请进行哈希,再对机房的数量进行取模,这样能够保障流量均匀分布到某个机房,然而对于某些申请来说可能速度会慢,比方一个新疆的申请,打到了广州机房,网络提早就会比打在西安机房大
  • 按地理位置分片,申请只会打在间隔本人最近的机房,解决申请的速度快,然而流量不平均

异地多活

把异地双活的思维推到多个城市,部署多个机房

本文由 mdnice 多平台公布

正文完
 0