数据库设计入门分布式架构

支付宝去O的关键技术之一——数据库弹性路由

2019-04-30  本文已影响0人  MQ4096


概述


  本文主要总结蚂蚁去O成功的关键技术之一——数据库弹性路由的原理以及对这个原理的思考。这个技术对传统行业技术而言也是可以实现的,它的思路对传统行业去O或者大机下移项目也有一定借鉴意义。 蚂蚁去O成功的其他关键技术还有分布式关系数据库OceanBase、微服务平台、消息队列、分布式事务、MPaaSBPaaS、全链路压测等。

        数据库弹性路由能力更大的作用体现在异地多活/容灾建设里,本文只讨论业务视角的数据库高可用问题,有点把弹性的能力说小了的意思。个人观点,难免偏颇,仅供参考。

数据库高可用方案回顾

       通常数据库如果出现故障了,最好最快的选择就是数据库做一个数据库切换,然后应用连接新的数据库,恢复对外服务。不过这个切换能做到多快(RTO),不同数据库产品的技术方案和能力不一样。此外即使有些RTO可以做到很短,但是可能不能保证不丢数据(RPO) ,最终业务还是不敢切换数据库。

  在传统金融行业,数据库RPO的优先级高于RTO。因此比较RTO大小必须是在RPO为0的前提下。表现最好的首先是数据库集群类产品,如ORACLERACSQL ServerCluster。然后是一些高可用产品,如IBMHACMPVeritasHA产品。这些方案都依赖共享存储,数据只有一份。当数据存储出现故障时还要依赖主备架构方案。如ORACLEDataguardSQL ServerMirror。这些方案的特点是只要主库事务日志复制到了备库,则RPO可以做到0,但是RTO通常是分钟级别。

  蚂蚁金服自研的分布式数据库OceanBase在保证RPO为0的前提下,在故障切换时将RTO做到理论最短14秒,从而业务异地容灾切换可以做到最短26秒的水平。当然业务集群规模大的时候,这个时间还会长一点,但基本也在一分钟以内。能做到这点关键一是OceanBase的快速异地切换能力,二就是应用的数据库弹性路由能力。

  在技术标准上没有最好,只有更好。在业务数据库规模集群很大以及高峰时,数据库即使最短14秒不可用对业务造成的损失也很大,还会有舆论压力。此外在高压力下,比数据库不可用更可怕的是数据库可用但是性能衰减(如访问延时RT增加,进而QPS能力下降),假如各级应用没有适当的自我保护能力,这个延时的增加很可能引起一批应用雪崩,业务损失更大。

  数据库的弹性路由技术就是应用自我保护能力的关键。在解释这个之前先从传统的数据库高可用方案说起。

数据库高可用方案要点


  数据库高可用是业务高可用的一部分。当数据库出现读写故障时,高可用方案都要实现两点功能:

  • 1. 数据库故障转移,恢复数据读写服务。

  • 2. 客户端数据库路由切换。

  • 数据库故障转移

      传统商业数据库都提供了故障转移方案,无论是集群架构还是主备架构。这些之前在文章《一些关系数据库的架构总结》里介绍了,属于数据库产品自身的能力。但是本文要总结的这个能力是尽可能的不依赖数据库的能力,这样才可以降低风险。

      分布式数据库相比传统集中式数据库,故障转移稍微有点变化。由于数据是分布在多个机器上,单个机器节点故障,只是部分数据访问不可用。所以通常只需要局部受影响的数据做故障转移。

    客户端路由切换

      数据库内部切换了,有可能提供服务的实际IP变了,为了不让应用修改数据库连接,也产生了多个技术方案。

      早期一些驱动产品(如odbcjdbc),都提供Connection Failover特性,允许配置一个备用数据源。通常当主数据源连接不上时会轮询备用数据源。在驱动端的Failover判断逻辑跟数据库的Failover并没有联动,只是靠探测决定。二者逻辑不一致时,这个特性就适得其反。因此这个方案不适合核心业务。

      ORACLE在连接方面的功能非常丰富和实用。有客户端的Failover方案。如在客户端配置文件tnsnames.ora里配置连接多个数据库IP(方法也是探测+轮询)。11g以后还增加SCAN特性。并且有运行时的Transparent Application Failover(简称TAF)和Fast Connection Failover(简称FCF)功能。这些功能不仅实现故障转移,还可以提供负载均衡的效果[2]。

      分布式数据库架构下,都会有一个角色负责内部数据路由。即使内部某个数据的访问发生切换,这个内部路由应该是也会切换的,而对应用而言访问方式还是不变。比如说OceanBase的OBProxy节点、TiDBTiDB Server节点等。这些节点都有个路由的作用,无状态的,可以部署多个。它们的作用更像是数据库的代理,它们的可用性也就代表了分布式数据库集群的可用性。所以实际部署时都会建议至少部署2个节点,然后前端接一个负载均衡设计(硬件实现就是F5,软件就是LVS等)。

    负载均衡设计主要承担后端路由节点的高可用,其次是负载均衡。同时负载均衡能提供一个统一的访问方式(如VIP)给应用(更好的做法是将该VIP绑定到一个域名上),所以理论上无论数据库端哪个环节发生切换,应用客户端都不需要改变。

    数据访问中间件解决方案

    TDDL的解决方案

      无论是客户端驱动里的Failover设计,还是负载均衡等设计,对数据库是否切换的判断策略都不是很灵活,不一定满足业务应用需求。所以业务应用会选择自己控制。这其中就诞生里数据访问中间件产品,如TDDLZDAL

      下面是TDDL公开的原理,对数据源做了三层管理。

  • 三层数据源每层都按JDBC规范实现,使得对前端应用没有任何代码侵入。 

  • Matrix层(TDataSource)实现分库分表逻辑,底下持有多个GroupDs实例。 

  • Group层(TGroupDataSource)实现数据库的主备/读写分离逻辑,底下持有多个AtomDs实例。

  • Atom层(TAtomDataSource)实现数据库连接(ipportpasswordconnec-tionProperties)等信息的动态推送,持有原子的数据源。

  • TDDL架构图

      即使没有做分库分表拆分也可以使用这个TDDL。应用通过APP名称沿着Matrix层找到对应的Group层信息,然后连接哪个Atom层就看各个Atom的权重设置。权重的定义包含读写权重。如r10w10表示提供读写,r10w0表示只读,承担100%的读流量, r0w0表示不提供读写,就是纯备库。r2w0表示承担20%的读流量。

      这个设计就使得读写分离,主备切换等很容易控制。比如说推送一个配置修改某个Group下的Atom的权重就行((数据库切换还是要数据库层面解决)。Alibaba的MySQL高可用产品(ADHA)在对数据库主备切换后就是调用配置管理接口修改客户端路由(Atom的读写权重)。不过权重跟实际数据库两者切换会有个节奏不同步问题,因此应用会碰到一些数据库读写失败或者只读的报错。

    蚂蚁数据访问中间件的解决方案

      蚂蚁也有分布式数据访问中间件ZDAL,功能基本类似。上面这个客户端路由切换方案的特点是影响是全部数据的访问。蚂蚁做了一些创新,做到不同数据库请求走不同的路由,动态访问。

      能做到这一点的关键首先是业务流量和底层数据都做里水平拆分,并且拆分维度保持一致。其次在业务ID(通常就是拆分字段)的结构里包含里目标数据源的信息。比如说XXXX01XXXXX 其中01表示访问主库,XXXX02XXXXX 其中02表示访问备库或者FO库(作用跟备库类似,但可以读写,后面介绍)。而具体是生成01还是02或者其他的值,通常由配置决定;还可以自定义规则(比如说某些特殊的用户启用这个路由,这就是数据访问灰度)。

      这个设计的好处就在于这个自定义规则的能力,这使得应用在判断是否该做数据库切换上由更多选择。比如说一个关键数据的服务化请求,如果发现数据库延时变大,通常应用会有两个选择。一是死扛,直到扛不住自己挂了;二就是自我限流保护,拒绝掉新的请求。现在还有第三个选择就是切换路由访问其他数据库。这个数据库不一定是备库,但有着备库的作用,蚂蚁称之为FO库(FO即:FailOver的意义)。

    业务FO库设计

      这个FO库有着备库一样的作用。它可以是物理备库。如果是物理备库,那客户端路由切换过去后会只能读不能写,所以也会有数据库的主备切换,那就是全部数据访问都换了个新主库。这跟传统主备切换就没什么不一样,RTORPO都不满足。

    初步看来这个设计似乎没什么用,但是有一类特点的业务可以利用这个FO库的设计。

    流水型业务的FO库设计

      流水型业务指的是交易流水、日志类业务。其特点是SQL多是INSERT,也有UPDATE,但是是对刚刚INSERT的数据做的更新。每笔业务事务跟其他业务事务没有直接关系,跟历史事务也没关系。

      流水线业务应用主要就是向数据库里写入新的交易流水。如果数据库不可用的时候,应用的请求ID中会切换路由到FO库,后续写入都到FO库。FO库初始状态是一个空库,表结构跟业务主库一致,但是没有数据。这样业务交易可以迅速恢复并持续可用。针对老的数据访问,由于其ID中有老的路由信息,还是会访问原主库。如果原主库是故障了,则有主备切换,老数据会访问到新的主库。虽然故障切换要点时间,不过只有部分老数据访问受损。

      流水线业务数据库的FO方案,把可用性的粒度做到用户级别(因为交易是按用户拆分的),是对可用性解决方案的一个很大的创新。此外这个FO库不需要有全部的数据也是跟物理备库最大的区别。一个空库为什么也可以满足业务需求?这背后的思想就是分布式里比较流行的BASE(Basic Available, Soft state, Eventual Consistency)理论。如下图

    BASE理论

      业务主库数据库性能下降或者不可用的时候就是分区开始,主库性能恢复或者新主库提供服务时路由改回去就是分区恢复。S2产生的数据可以合并或者不合并回业务主库。

    状态型业务的FO库设计

      也不是所有业务都像交易那样新事务跟历史数据无关。如帐务数据等,大部分是老账户数据的更新操作。如果像上面的设计思路一样,那只能保证新开的账户业务能正常处理,这部份业务占比不高。业务应用仍然要想办法提升老用户的用户体验。一个可行的思路就是在应用架构设计上将一个业务更新操作转换为一个数据库的插入操作。那么使用同样的空库就可以在新的FO库响应应用的插入和后续更新请求。比如说在转账支付业务中,当账户余额库出现性能问题或者故障时,业务可以快速选择下一个支付渠道(如银行卡充值)充值支付。充值时这个金额并不需要立即加到余额上(那会是一个更新操作),而改为存在另外一个地方(那是一个插入操作),随后的业务转账逻辑继续。此时如果要查询用户的余额时,就需要将物理备库(只读)的余额数据(S1)和FO库的临时余额(S2)合并展示。

      当然这个方案并不能解决所有场景的可用性问题。当用户要扣减当前余额时,在业务主库没有恢复服务之前是满足不了的。状态型业务的FO库的数据是要合并回业务主库的,这个需要借助外部数据同步产品。

            此外也不是所有的业务都能应用这个转换的小技巧。因此还有一种方案就是使用一个逻辑备库作为FO库。逻辑备库只可以开启读写的实例,其数据是从主库那里同步过来的,需要一个外部数据同步产品。逻辑备库不保证实时,可能有延时。当启用逻辑备库的时候,应用中间件层有办法拦截那些最新数据还没有同步到备库的用户(即临时放入黑名单)。这些用户数据往往就是在路由切换之前那短时间内对主库有个更新操作的数据。逻辑备库做FO库的好处是比物理备库切换的块,而数据不一致的处理策略就是将不一致数据的用户进行拦截,避免它在脏数据上进行操作。当同步追平后黑名单自然解除。当使用OceanBase替换ORACLE后,这个外部数据同步就不用了。

    FO库设计的前提和问题

      要发挥FO库的作用有几个前提:

  • 业务做水平拆分,并且分析其特点看是否实现这种最终一致的效果和业务能否接受这个最终一致。

  • 数据访问层中间件支持这种在业务数据的关键字段和服务化调用之间的请求信息里包含路由信息。

  • 数据库层面要有主备切换机制并保证不丢数据。

  • 数据库外部有数据同步产品。

  •   同时,引入FO设计也会引入一些麻烦。比如说因为弹性路由引发的分布式事务。

    数据库弹性路由跟OceanBase关系


      应用有了数据库弹性路由能力后可以应对数据库(包括ORACLE)的可用性问题,性能衰减问题,降低了对数据库稳定性的依赖,也降低了使用OceanBase替换ORACLE的系统风险。

      数据库弹性路由能力更大的作用体现在异地多活/容灾场景里,同时结合OceanBase的异地多活能力,实现蚂蚁的各个机房间的流量可以做到很细粒度的随意弹性切换。在弹性能力上,两者各有特色。

    参考

  • [1]玄霄, 

    从“挖光缆”到“剪网线”|蚂蚁金服异地多活单元化架构下的微服务体系

  • [2]崔华,Oracle RAC 环境下的连接管理 https://www.oracle.com/technetwork/cn/articles/database-performance/oracle-rac-connection-mgmt-1650424-zhs.html

  • [3]玄霄, 

    分布式系统数据层设计模式

  • 推荐阅读:

    如何基于OceanBase构建应用和数据库的异地多活

    上一篇下一篇

    猜你喜欢

    热点阅读