zoukankan      html  css  js  c++  java
  • 数据库的异地多活分析和方案

    https://cloud.tencent.com/developer/article/1421904

    前言


    前文提到异地多活的几种型态和基于OceanBase实现方案。这里再总结一下基于其他分布式数据库(MySQL)实现异地多活时要考虑的点。本文不讨论为什么做异地多活,可以参考末尾的文章。

    异地多活的目标


    首先引用前文的分析。

    异地多活的概念一直都有,只是内涵不断变化。以双机房多活为例,应用通常都是无状态的,可以多地部署。数据库有状态,传统数据库只有主库可以提供读写,备库最多只能提供只读服务(如ORACLE的Active Dataguard): 1. 应用双活,数据库A地读写,B地不可读写。这种只有应用多活,数据库是异地备份容灾(无并发)。 2. 应用双活,数据库A地读写,B地只读。这种也是应用双活,数据库读写分离(实例级并发)。 3. 应用双活,数据库双活,两地应用同时读写不同表。这种数据库双向同步,应用同时错开写不同的数据(表级并发)。 4. 应用双活,数据库双活,两地应用同时读写相同表不同记录。这种数据库双向同步,应用同时错开写不同的数据(行级并发)。 5. 应用双活,数据库双活,两地应用同时读写相同表相同记录。这种数据库双向同步,应用同时写相同的数据,最终会因为冲突一方事务回滚(行级并发写冲突) 上面第1种情形,B地应用是跨地域远程读写数据库。两地距离较大的时候性能会很不好。2的B地应用是本地访问数据库。3,4,5三种情形两地数据库都提供读写服务,对应用而言是本地访问数据库,但到分布式数据库内部,其要读写的数据是否正好在本地就取决于业务和数据库的拆分设计。

    首先确定要实现的异地多活目标肯定不是1和2这种。

    其次,3,4,5都需要应用做水平拆分。OceanBase的每个分区只有一个Leader副本提供读写,所以只通过分区表做水平拆分的时候只能做到3。MySQL的Group replication基于分布式一致性算法(Paxos协议的变体)实现了多主更新复制协议,可以双写或多写,对原来主从复制架构是个突破。但是面临并发更新同一笔记录时会出现冲突,后提交的事务会回滚。所以MySQL Group replication实现了第5种形态。如果应用层流量拆分做的好的话,规避冲突,可以实现第4种形态。

    不过这个方案在数据同步性能上有瓶颈。

    最后,3和4两种形态,应用都是本地读写数据库(即单元化,单元内请求自封闭)才有意义。后面主要讨论如何基于分布式MySQL实现第4种异地多活。

    异地多活的困难


    异地多活的目标很吸引人,但是技术门槛也很高。说光靠一个数据库或者一个数据传输产品就可以做异地多活是很片面的。

    业务要先做垂直拆分

    如果要做异地多活的业务很大,通常需要先按模块垂直拆分为多个独立的应用,针对每个独立的模块应用做异地多活设计会更可行一些。具体拆分到什么粒度要看子应用能否做水平拆分。垂直拆分要求数据是分开存储(分到不同的Database或者Instance等);应用做服务化,彼此解耦。

    应用要能做水平拆分

    做异地多活要尽可能的避免应用跨地域读写数据库,那么同一个用户请求就只应该出现在某个机房的应用里,不同用户的请求可能分布在不同机房。应用的流量按照用户做水平拆分了。满足这个条件的应用的数据也按相同维度做水平拆分,则每个机房的应用都可以同时本地读写数据库。

    确定不同应用的单元化类型

    上面这类应用形态在阿里巴巴电商异地多活架构方案里叫Unit类型应用,在蚂蚁金服里叫RZone(Region Zone)应用。特点就是每个单元(机房)自封闭(包含),多点并发读写。(当然是读写不同记录)。多个单元之间写入的数据不一样(不冲突),理论上单元的数据不需要包含所有数据,不过为了实现动态调整单元间的流量或者做在线容灾切换,实践时,每个单元还是包含全部数据。所以单元间需要双向同步数据。三单元时为降低技术复杂度,选一个单元做为中心节点,其他两个单元都只跟中心节点做双向数据同步。

    不过不是所有的应用都可以设计为Unit类型。比如说两个业务有关联的应用A和B,拆分维度却不同时,A设计为Unit类型,业务上A和B会有一些关联,即使应用采用了服务化改造,A请求B的时候按照B的拆分维度访问,并不一定能保证B中要访问的数据一定跟A中要访问的数据在同一个单元。即有可能出现A应用的分片跟B应用的分片是交叉访问,应用之间会出现很多跨地域的请求,这个是不能接受的。

    所以,A和B当中只能选择一个应用改造为Unit类型,另外一个应用的数据就是在中心集中读写。如果A对B的依赖只是读依赖且能接受延时,那么可以把B的数据同步一份全量到其他单元,这样至少实现了每个单元都是本地读,中心集中写。这样的单元化应用类型在阿里巴巴电商异地多活架构方案里叫Copy类型应用,在蚂蚁金服这个类型叫CZone。如果应用A不能接受B的延时读,则只能跨地域访问中心读。蚂蚁金服叫这个类型为GZone。应用能不能接受延时读是要在性能和数据一致性之间取一个平衡。

    单元间的数据同步问题

    应用的单元化类型确定后,数据同步的方向就定了。由于是跨地域的,MySQL的原生复制(Replication)的并发和吞吐量太低,且很容易因为实例异常出现同步中断。所以单元间的数据同步都是通过独立的数据传输产品DTS实现的。

    DTS的数据同步就是全量同步加增量实时同步,增量通过兼容MySQL的slave连接协议获取MySQL的增量,然后利用压缩、并行和批量技术传输到其他单元并应用。性能比原生复制好很多。

    双向同步会是一个难点,需要MySQL内核里对Binlog每笔事务记录一个标识符,DTS在同步增量的时候会读取这个标识符,以避免将增量又应用到源端去了。即避免循环复制。

    跟MySQL原生复制一样,面临两边数据不一致的时候,DTS需要决策是中断还是跳过。这里依然会要求有很高的数据一致性。所以DTS在同步的过程中必须有全量校验机制和增量校验机制。不过由于是独立于MySQL的同步,也会存在延时或错误,理论上还是无法保证两边数据实时强一致。对数据一致性要求非常高的应用需要有业务层面的一致性校验逻辑。如金融行业的对账逻辑、电商库存的比对逻辑等。

    数据延时也是一个风险,应用需要有相应应对逻辑。当一个单元大量数据延时,可能需要决策将这个单元的业务流量切换到其他单元(即放弃这个单元)

    单元流量切换问题

    在异地多活中,每个单元承担了一定比例的流量,总和就是100%。实际中运维或者业务都可能需要调整单元间的流量配比。如果彻底拿掉某个单元的流量,就是我们说的切换。在流量调整过程中,一个处于业务流程中的订单记录随后的访问流量可能恰好切换到异地单元,但是数据同步不巧又有延时,此时用户读取的数据就是有延迟的数据(不是最新的数据),很容易会恐慌或者误操作。比如说下单支付后碰到流量切换,刷新订单状态发现依然是未支付状态。匆忙间可能又重新支付一次等等。应用需要应对此类数据延时做处理。通常策略就是“禁止更新”——不允许应用对订单做任何修改。等数据同步赶上再恢复操作。

    这里还有个问题就是不同模块的应用,数据延时都不同,不可能要等所有数据同步都追赶上才恢复。所以整体业务需要选择以哪个应用的数据同步延时为准。选择后,其他应用的数据同步延时就不在“禁止更新”策略里考虑了。所以,单元流量动态切换,或者异地容灾切换也会在可用性和数据一致性之间做一个权衡。由此带来的问题就需要运维人员去修复,不管是人肉还是通过工具自动化,都不是那么省心的事情。

    异地多活架构方案


    基于分布式MySQL的异地多活方案

    上图是阿里巴巴电商异地多活技术架构。

    l 在接入层前面会有个全局的用户分流逻辑

    l 数据库AliSQL,每个单元主备架构,每个单元都有全量数据。

    l 单元之间的数据同步用DTS,单元布局是星形结构,每个单元跟中心节点做双向同步。单元间存在同时读写同一个分表,但是不会同时写同一笔记录。

    l 缓存产品在单元间的数据同步有些是走产品自身复制技术,有些是通过DTS的订阅功能去更新缓存。

    l 存在一些业务时Copy类型,只能在中心写,被其他Unit型应用强依赖。

    基于X-DB的异地多活方案

    X-DB是阿里巴巴MySQL内核团队继AliSQL后推出的一个MySQL数据库,主要特点是在MySQL里引入Paxos协议实现多副本(并有自己的创新),可以做到副本间强一致,并在Leader副本故障时能自动切换且不丢数据。X-DB本身还不具备分库分表能力,还需要结合分布式数据库中间件一起做。

    上图是X-DB跨城部署的日常状态。在大促的时候,由于应用访问流量非常大,X-DB可以灵活调整为大促状态,如下所示

    XDB解决了数据同步问题、故障切换和数据一致性问题。所以不需要借助数据传输产品。

    基于OceanBase的异地多活方案

    这个方案在前文里已经详细介绍。

    基于OceanBase和基于分布式MySQL方案的共同点都是有拆分(分区或分表),不同点有很多。撇开OceanBase在高可用和强一致的优势外,很重要的一点就是分布式MySQL的不同单元之间的集群只是逻辑上有联系,集群之间内部数据并无联系,而在OceanBase里,不同单元之间共同构成一个集群,所以每个数据(分区)的不同副本之间是有内在联系的(也可以称约束)。

    在OceanBase里每个分区只有一个leader副本,也就是对应用而言,只有一个读写入点。而在分布式MySQL里,相同的分表多个单元都可以同时写入,并彼此同步,只要不是写同一份数据即可。这是分布式MySQL方案的优势。所以基于OceanBase构建的异地多活方案种,用户流量迁移的粒度就是分片数的倒数,而基于分布式MySQL构建的异地多活方案中,用户流量的分配更加灵活,粒度更细。

  • 相关阅读:
    如何在github中的readme.md加入项目截图
    git图片无法正常显示
    PHP错误:SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
    Mac安装PHP运行环境
    YII2数据库操作出现类似Database Exception – yiidbException SQLSTATE[HY000] [2002] No such file or director
    composer 安装 Yii2遇到的BUG
    js中字节B转化成KB,MB,GB
    README.md编写教程(基本语法)
    微信扫码网页登录,redirect_uri参数错误解决方法
    记录下自己亲自做的Django项目继承QQ第三方登录
  • 原文地址:https://www.cnblogs.com/dhcn/p/12336603.html
Copyright © 2011-2022 走看看