分布式系统下,分布式数据库遇到的挑战

 

  分布式系统下,当访问关系型数据库的i/o占用过高,内存不足,访问过慢的情况下,可以考虑流流行的分库分表的策略,但是这样也会到来很多新的技术挑战。

 

1.分布式事务

 

  当还是单体应用,单体数据库时,完全不需要考虑事务的一致性问题,因为mysql已经帮我们处理事务问题(ACID),但是这只是针对单体情况下,如果是多个数据库,主从备份,读写分离,那么就会可能造成事务不一致的情况,那么什么事分布式事务,分布式

  事务又该如何解决呢?

  

  1.有关于事务的概念

    本地事务:本地事务的优点就是支持严格的ACID特性,高效,可靠,状态可以只在资源管理器中维护,而且应用编程模型简单。

    全局事务:当事务由全局事务管理器进行全局管理时成为全局事务,事务管理器负责管理全局的事务状态和参与的资源,协同资源的一致提交回滚。

    两阶段事务:两阶段事务提交采用的是X/OPEN组织所定义的DTP模型,通过抽象出来的APTMRM的概念可以保证事务的强一致性。 其中TMRM间采用XA的协议进行双向通信。 与传统的本地事务相比,

          XA事务增加了prepare阶段,数据库除了被动接受提交指令外,还可以反向通知调用方事务是否可以被提交。 因此TM可以收集所有分支事务的prepare结果,最后进行原子的提交,保证事务的强一致性。

      

    BASE理论:BA指的是基本业务可用性,支持分区失败,S表示柔性状态,也就是允许短时间内不同步,E表示最终一致性,数据最终是一致的,但是实时是不一致的。原子性和持久性必须从根本上保障,为了可用性、性能和服务降级的需要,只有降低一致性和隔离性的要求。

       CAP定理:对于共享数据系统,最多只能同时拥有CAP其中的两个,任意两个都有其适应的场景,真是的业务系统中通常是ACID与CAP的混合体。分布式系统中最重要的是满足业务需求,而不是追求高度抽象,绝对的系统特性。C表示一致性,也就是所有用户看到的数据是一样的。

         A表示可用性,是指总能找到一个可用的数据副本。P表示分区容错性,能够容忍网络中断等故障。

 

  2.解决方案

    1.两阶段(2PC)解决方案

      

 

      

        两阶段提交其实比较简单,这边有两个资源提供准备和提交两个接口。

        由于隔离性互斥的要求,在事务执行过程中,所有的资源都是被锁定的,这种情况只适合执行时间确定的短事务。 但是为了保证分布式事务的一致性,大都是采用串行化的隔离级别来保证事务一致性,这样会降低系统的吞吐。

        但因为2PC的协议成本比较高,又有全局锁的问题,性能会比较差。 现在大家基本上不会采用这种强一致解决方案。

 

    2.TCC事务补偿方案

                                    

 

            

              TCC名字的由来是其中包含了 try, confirm, cancel三个操作。

              与两阶段提交相比,TCC位于业务服务层, 没有单独的准备阶段,Try操作可以灵活选择业务资源锁的粒度。TCC是通过最终一致性来解决系统性能问题的这个设计,对我们设计抉择有很大的启发。 有些时候系统的技术问题是可以通过业务建模的方式来解决的。

 

 

    3.Saga事务

      Saga这个概念来源于三十多年前的一篇数据库论文Sagas ,一个Saga事务是一个有多个短时事务组成的长时的事务。 在分布式事务场景下,我们把一个Saga分布式事务看做是一个由多个本地事务组成的事务,每个本地事务都有一个与之对应的补偿事务。

      在Saga事务的执行过程中,如果某一步执行出现异常,Saga事务会被终止,同时会调用对应的补偿事务完成相关的恢复操作,这样保证Saga相关的本地事务要么都是执行成功,要么通过补偿恢复成为事务执行之前的状态。

      Saga定义了一个事务中的每个子事务都有一个与之对应的反向补偿操作。由Saga事务管理器根据程序执行结果生成一张有向无环图,并在需要执行回滚操作时,根据该图依次按照相反的顺序调用反向补偿操作。Saga事务管理器只用于控制何时重试,何时补偿,

      并不负责补偿的内容,补偿的具体操作需要由开发者自行提供。

 

       

      SAGA可以看做一个异步的、利用队列实现的补偿事务。

      其适用于无需马上返回业务发起方最终状态的场景,例如:你的请求已提交,请稍后查询或留意通知 之类。

      将上述补偿事务的场景用SAGA改写,其流程如下:

      •     订单服务创建最终状态未知的订单记录,并提交事务
      •     现金服务扣除所需的金额,并提交事务
      •     订单服务更新订单状态为成功,并提交事务

    以上为成功的流程,若现金服务扣除金额失败,那么,最后一步订单服务将会更新订单状态为失败。

    其业务编码工作量比补偿事务多一点,包括以下内容:

      •     订单服务创建初始订单的逻辑
      •     订单服务确认订单成功的逻辑
      •     订单服务确认订单失败的逻辑
      •     现金服务扣除现金的逻辑
      •     现金服务补偿返回现金的逻辑

    但其相对于补偿事务形态有性能上的优势,所有的本地子事务执行过程中,都无需等待其调用的子事务执行,减少了加锁的时间,这在事务流程较多较长的业务中性能优势更为明显。同时,其利用队列进行进行通讯,具有削峰填谷的作用。

    因此该形式适用于不需要同步返回发起方执行最终结果、可以进行补偿、对性能要求较高、不介意额外编码的业务场景。

    但当然SAGA也可以进行稍微改造,变成与TCC类似、可以进行资源预留的形态。

 

    4.基于消息事务    

      基于消息实现的事务适用于分布式事务的提交或回滚只取决于事务发起方的业务需求,其他数据源的数据变更跟随发起方进行的业务场景。

      举个例子,假设存在业务规则:某笔订单成功后,为用户加一定的积分。

      在这条规则里,管理订单数据源的服务为事务发起方,管理积分数据源的服务为事务跟随者。

      从这个过程可以看到,基于消息队列实现的事务存在以下操作:

      •     订单服务创建订单,提交本地事务
      •          订单服务发布一条消息
      •     积分服务收到消息后加积分

    我们可以看到它的整体流程是比较简单的,同时业务开发工作量也不大:

      •     编写订单服务里订单创建的逻辑
      •     编写积分服务里增加积分的逻辑

      可以看到该事务形态过程简单,性能消耗小,发起方与跟随方之间的流量峰谷可以使用队列填平,同时业务开发工作量也基本与单机事务没有差别,都不需要编写反向的业务逻辑过程。因此基于消息队列实现的事务是我们除了单机事务外最优先考虑使用的形态。

 

    单机事务》基于消息的事务》基于补偿的事务》TCC事务
posted on 2019-11-30 16:01  流星划过天际  阅读(756)  评论(0编辑  收藏  举报