栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > 架构设计

【分布式】异地多活

架构设计 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【分布式】异地多活

  常见的多活方案有同城双活、两地三中心、三地五中心、异地多活等,异地多活是目前比较普遍的一种。作为一种分布式系统架构,其核心目的是维护系统的的高可用性。那既然要提高容灾,一定涉及到冗余。

两地三中心
  • 两地:本地 + 异地
  • 三中心:本地主数据中心 + 本地数据备份中心 + 异地数据备份中心

  两地三中心是一种成熟的服务器灾备解决方案,可以视为同城双活+异地多活。数据中心间存在三种备份方式,前两种统称为主备模式(Active-Standby):

  1. 热备:服务器A1作为主服务器承担业务,服务器A2作为备份服务器,实时从A1中获取数据保持数据一致。一旦A1熄火,A2立即接手保持服务正常不间断运行。由于时刻有一个A2空转作为备份,因此开销巨大。
  2. 冷备:依旧只有A1承担业务,只不过A2不再时刻保持数据一致,而是周期性地同步A1数据,即异步数据复制。实际上是在A1完成所有服务、离开工作状态、数据库关闭后进行复制,这确实可以避免复制过程中写入数据导致的一致性问题,并且直接用系统的指令去复制,很简单。A1瘫痪,来不及拷贝的业务直接中断,在业务层上判断和处理故障。但是冷备的问题是,在异地采取冷备,一旦遇到故障,很难决定是否要切换备份中心。因为连接到备份中心的时间未知(不知道能不能切换过去),备份中心接管服务的时间未知,接管后功能是否正常也未知。并且冷备基本上就是备份全站,成本并没有比热备低很多。
  3. 双活(Active-Active):这种方式对服务器的利用率最高。A1和A2同时承担业务,作为主服务器的A1负载相对高一点(可能达到总体服务量的六成到七成)。并且A1和A2互相备份,且实时备份。双活分为两种,同城双活和异地双活。

  两地三中心的优势很明显,服务同城双活,数据通城灾备,通信便捷,很多异地多活里棘手的问题(时延、同步、一致性)在同城双活中根本不叫问题。但是同城双活的问题就是数据库写数据存在跨机房调用。
  同城双活+异地双活的架构解决了同城双活无法解决的跨地区容灾问题。异地的备份中心可以是冷的,也可以是活的,但是也解决不了跨机房调用,并且异地的话没有骨干网,延迟是很大的,因此很多情况下是冷的。并且这也带来冷备的问题:出了问题很难决定要不要把流量切刀备份中心。

异地多活

  说到底,这个架构仍旧是一个分布式架构,那就不可避免地需要面临分布式架构的三大问题:计算、存储、通信。而实际案例中,往往更关注存储和通信两部分。解决整个系统的问题,其实主要涉及两个部分:业务划分和数据划分。所谓业务划分,就是把一套核心业务包装成一个单元,单元内部需要保证高度的一致性。而数据划分则是对所有的数据进行维度上的划分,去选择一个维度作为我们所设计的单元的输入。
  因此,双活架构在两个机房的调用是各自封闭的,不存在跨机调用的情况,只需要在底层做好数据同步。并且两个站点是同时承载不同的流量的,这就要根据一些业务属性来分配,比如用户ID、所属地域等等策略,这里为的就是能够在数据层面也要做好隔离,一个站点内只提供固定部分的用户访问。这样就保证了单站点内同一分片的数据,不会在另外一个站点被变更,后续的同步也可以做到单向。这个数据切片的目的本质根据业务数据自身的特性进行流量切分。
  事实上,由于异地多活的布置难度很大,它只是一个可选方案而非必选方案。在当前数据中心机器资源不够的情况下,就没必要把业务一点一点拆分出来异地多活,直接整业务迁移,选择一个离主机房比较近第二机房用来扩展,尽量留出多的本地的机器资源给核心业务,如果机器还是不够,再考虑多活。(主机房和第二机房延迟尽量在10ms以内,用于对照的是京-沪两地延迟30ms)。异地双活比较常见,但是一旦从双活变成三活,这个新机房想接入这个同步系统成本就很高了,不过容灾本身就是高投入高回报的事情,对吧。
  并且,并非所有业务都适合单元化。游戏、电商、邮箱等服务,就比较适合单元化,因为用户便于分区。但是社交软件由于关系公用等问题,就不适合分区。另外,金融业务这类实时强一致性业务也不是很适合异地多活。
  最后,异地多活要解决的是“高可用性”问题,并非“百分百可用”,适当地舍弃一些服务,换取整体的稳定运行,是值得的。但是,异地多活只是多种架构中的一种,它有自己的优势,也有自己的劣势,在适合的场景下会大放异彩,而并非通用的解决方案。

(异地多活有四个值得关注的地方,在本节内用红色字体标出 )


案例一

  以下内容整理自 原文链接 原文链接。

挑战1:延时

  异地项目中,跨城市一定会有延时的问题。在中国范围内,延时可能在一百毫秒以内。看起来单次好像没什么,但是像淘宝是个很大的分布式系统,一次页面的展现,背后的交互次数可能在一两百次。如果这一两百次全部是跨城市做的,整个响应时间会增加很多,所以延时带来的挑战非常大。

【解决方案】

  让操作全部在同一机房内完成,即减少数据中心间的通信次数。在并行计算课程中,也提到分布式系统的通信主要分为两部分:本地通信和远程通信。本地通信的开销远远小于远程通信。

  怎样让所有操作在一个机房内完成?单元化。
  所谓单元化,其实就是根据业务特点对所有的业务进行类型划分。出于成本的考量,多活情况下备份全站是不现实的,即:并非所有业务都需要异地多活 。那有哪些服务需要备份呢?

  核心业务。怎么判断一个业务是不是核心业务呢?最简单的依据是流量。比如一个网站提供用户注册、登录、个人信息修改的服务,一天之内,可能有百万级用户登录、十万级用户注册和修改个人信息,那登录就是核心业务。再比如淘宝,那与交易相关的业务肯定也是核心业务,非交易类型的功能就不是核心业务。
  换句话说,核心业务就是流量峰值高的业务(比如双十一的淘宝),这些业务尽管配备了冗余,还是会面临某一时间点访问量暴增的情况,所以需要异地部署。流量小的、用的不多的业务,不用异地部署。
  把一组核心业务单元化的另一个重要依据是:服务间的依赖

  因此在异地部署的并非全站,而是一组业务,这组业务就成为单元,即当前案例中的交易单元。

挑战2:数据一致性

  这是分布式数据库老生常谈的话题,将业务封闭成单元进行异地部署后,如果多地的相同单元同时写一行数据,就会出现冲突。因此在某个时间点,必须确保单行的数据在一个地方写,绝对不能在多个地方写。

【解决方案】

  为了做到这一点,必须确定数据的维度。如果数据只有一个维度,就像Facebook的数据,可以认为只有一个维度,就是用户。但是像淘宝,如果要在淘宝上买一个东西,除了用户本身的信息以外,还会看到所有商品的数据、所有卖家的数据,面对的是买家、卖家和商品三个维度。这时就必须做出一个选择,到底用哪个维度作为唯一的一个封闭的维度。

  单元化时,走向异地的就是买家的核心链路,所以选择了买家这个维度(意思就是卖家和商品在“购买”这个动作发生时其实相对来说是不怎么变动的,访问卖家和商品信息的是买家)。但是这样自然会带来一个问题,因为现在有三个维度的数据,当操作卖家商品数据时,就无法封闭了,因为这时一定会出现需要集中到一个点去写的现象。

实现难点

(一)路由的一致性

  所谓路由一致性,就是通过一个路由算法,保证从用户1进入淘宝、访问前端、前端页面再访问后端服务、后端访问数据库…这一系列操作一定要在同一个单元里。换句话说,这个“单元”并非是像事务一样的东西,它不是在语法规则上强制原子化的,它的“单元化”依赖于人的设计,是设计者通过把一堆东西强制放在同一个地方执行,这堆东西才能变成单元。
  路由一致性,实质就是把这些操作隐式地封装到一起变成单元。如果用户1本来应该进入城市A的数据中心,却因为路由错误进入B城市,那就破坏了这种“单元性”,那数据可能就出错了。同时也能说,相较于同城容灾中使用DNS导流的方法,异地容灾采取的是按用户分流的方法。

(二)数据同步的延时

  这个很好理解,如果多个备份间同步数据的延迟太大就不好了。注意,追求的是最终一致性,而非实时一致性。因为异地延时的影响因素太多了,而且主要是网络上的,比如网线被挖断了、网络故障等等。一个解决方案就是搭建专用的城际骨干网。这个案例要求在全国的范围内,都必须做到一秒内把数据同步完。
  在同步数据的过程中,并非只能使用存储系统的同步功能。MySQL自身的同步功能可以适用于大多数情况,但是在网络波动大、或数据量较大的时候就很慢。因为它的同步是一种单线程的复制,就算对同步过程进行监控,也只能干等着,啥也做不了。而Redis 3.0之前没有Cluster功能,只有主从复制功能,而为了设计上的简单,Redis主从复制有一个比较大的隐患:从机宕机或者和主机断开连接都需要重新连接主机,重新连接主机都会触发全量的主从复制。
  一个好的方法是扩展消息服务,从中间件或者服务层面直接支持跨机房消息同步,将消息体大小控制在10k以下,跨机房消息同步的性能和成本都比较可控。机房间的数据一致性只通过消息同步服务解决,机房内部解决缓存等与消息的一致性问题。跨机房消息同步的核心点在于消息不能丢,一个例子是微博,由于其使用的是MCQ,通过本地写远程读的方式,可以很方便的实现高效稳定的跨机房消息同步。
  二次读取也是好的方法。某些情况下可能出现消息队列同步也延迟了,用户在A中心注册,然后访问B中心的业务,此时B中心本地拿不到用户的账号数据。为了解决这个问题,B中心在读取本地数据失败的时候,可以根据路由规则,再去A中心访问一次(这就是所谓的二次读取,第一次读取本地,本地失败后第二次读取对端),这样就能够解决异常情况下同步延迟的问题。

(三)数据的正确性

  尽管多活成本低,但是以往的异地项目都更倾向于冷备,因为数据的正确性很难保证。数据在多点同时写的时候,一定不能写错。因为数据故障跟业务故障还不一样,跟应用层故障不一样。如果应用出故障了,可能就是用户不能访问。但是如果数据写错了,对用户来说,就彻底乱了。而且这个故障是无法恢复的,因为无法确定到底那里写的才是对的。这是最大的挑战,也是整个方案的第一原则。业务这一层出故障都可以接受,但是不能接受数据故障。

(四)数据的一致性

  一方面,每个单元都需要卖家的数据、商品的数据;另一方面,单元不是全量业务,那一定会有业务需要这个单元,比如说买家在这个单元下了一笔定单,而其他业务有可能也是需要这笔数据,否则可能操作不了,所以需要同步该数据。所以怎样确保每个单元之间的商品、卖家的数据是一致的,然后买家数据中心和单元是一致的,这是非常关键的。还有就是,如果两个多活的中心出现物理上的变动,比如增减机器了,也需要核对数据保证一致性。


案例二

Part 1 Part 2 Part 3 Part 4
  与同城多活的方案不同,异地多活的方案会限制机房间的相互调用,需要定义清晰的服务边界,减少相互依赖,让每个机房都成为独立的单元,不依赖于其他机房。(单元化)

  饿了么的服务和地理位置强相关,并且实时性要求高,多活设计最重要的是满足服务的地域性和实时性。

  可用性优先:当发生故障切换机房时,优先保证系统可用,首先让用户可以下单吃饭,容忍有限时间段内的数据不一致,在事后修复。每个机房都会有全量的业务数据,当一个机房失效后,其他的机房可以接管用户。用户在一个机房的下单数据,会实时的复制到其他机房。(服务特性是不同的,只能说在满足服务特性的条件下去让这个多活系统支持一些功能,所以每个多活系统的特点大致相同,但会各有倚重)

主要逻辑 (一)服务划分(Sharding)

  对服务进行分区,让用户,商户,骑手能够正确的内聚到同一个机房覆盖的范围中。分区方案是整个多活的基础,它决定了之后的所有逻辑。根据饿了么的业务特点,自然地选择地理位置作为划分业务的单元,把地理位置上接近的用户,商户,骑手划分到同一个区域,这样一个订单的履单流程就会在一个机房完成,能够保证最小的延时,在某个机房出现问题的时候,也可以按照地理位置把用户,商户,骑手打包迁移到别的机房即可。

  饿了么解决了三个问题:

  1. 如果两个城市是接壤的,会出现商家和用户处于不同 ezone 的情况,岂不是破坏了内聚性原则?
    ——选择更合理的划分地区的方式(基于地理信息的)。
  2. 用户是会动的,如果用户从北京到了上海,那么划分规则应该怎么应对?
    ——这其实就是 ipv4 异地访问的问题,饿了么用 Globa Zone 去解决。这种异地访问肯定会议延迟,大多数情况下是可以接收的。
  3. 3.为什么不简单点,按照用户的ID来切分?
    ——阿里是按照用户ID的取模来划分单元的(案例一),比较简洁,但这个服务强地域性,如果按照ID就会破坏单元化,出现跨机房调用。
(二)流量路由

  基于地理位置划分规则,我们开发了统一的流量路由层(API Router),最基础的分流标签是地理位置,即根据地理分流,当然还考虑了其它的因素。案例一其实就是按照用户去分流的。

(三)数据复制

  为了实现可用优先原则,所有机房都会有全量数据,这样用户可以随时切换到其他机房,全量数据就需要对数据进行实时复制。饿了么开发了相应的中间件,对 mysql,zookeeper ,消息队列和 redis 的数据进行复制。

(四)切换过程和异常保护

  在网络断开,或者是切换过程中,特别容易产生错误数据。比如由于复制延时,订单状态不一致,用户有可能会重复支付。

解决方案:

  1. 在网络中断时,如果不是必要,不做切换,因为任意单个机房能够提供完整服务;
  2. 如果需要切换,对锁定切换过程中的订单,直到切换完成,数据复制正常,才开放锁定。这个过程也通过 DAL(mysql 中间件)来实现;
  3. 对于标记为其他机房的写入数据,DAL 会进行保护,拒绝写入;
  4. DRC (中间件,支持异构数据库实时同步,数据记录变更订阅服务)会检查并报告错误的写入操作,方便检查隐藏问题。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/912450.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号