1、背景

     最近在研究分布式系统,其中有一个问题一直困扰着自己;事务问题,查阅资料和自己实践,写出来供大家参考。

2、传统事务(数据库事务)

    关系型数据库如果支持事务必须满足4个特性,分别是原子性(Atomicity )、一致性( Consistency )、隔离性( Isolation)和持久性(Durabilily)简称ACID。否则在事务过程(Transaction processing)当中无法保证数据的正确性。具体的细节内容,大家可以参考百度文库。传送门。这里不多做介绍。

3、分布式事务

    技术发展到现在,传统的垂直架构已经不能满足互联网模式的需求,分布式架构孕育而生。优秀的架构如阿里的Dubbo/Dubbox,和这两年火起来的Spring Cloud。这里不多做介绍,我们重点讨论分布式事务。当我们的单个数据库的性能产生瓶颈的时候,我们可能会对数据库进行分区,这里所说的分区指的是物理分区,分区之后可能不同的库就处于不同的服务器上了,这个时候单个数据库的ACID已经不能适应这种情况了,而在这种ACID的集群环境下,再想保证集群的ACID几乎是很难达到,或者即使能达到那么效率和性能会大幅下降,最为关键的是再很难扩展新的分区了,这个时候如果再追求集群的ACID会导致我们的系统变得很差,这时我们就需要引入一个新的理论原则来适应这种集群的情况,就是 CAP 原则或者叫CAP定理,那么CAP定理指的是什么呢?

3.1、CAP理论

CAP定理是由加州大学伯克利分校Eric Brewer教授提出来的,他指出WEB服务无法同时满足一下3个属性:

  • 一致性(Consistency) : 客户端知道一系列的操作都会同时发生(生效)

  • 可用性(Availability) : 每个操作都必须以可预期的响应结束

  • 分区容错性(Partition tolerance) : 即使出现单个组件无法可用,操作依然可以完成

具体地讲在分布式系统中,在任何数据库设计中,一个Web应用至多只能同时支持上面的两个属性。显然,任何横向扩展策略都要依赖于数据分区。因此,设计人员必须在一致性与可用性之间做出选择。

这个定理在迄今为止的分布式系统中都是适用的! 

3.2、Base理论

在分布式系统中,我们往往追求的是可用性,它的重要程序比一致性要高,那么如何实现高可用性呢? 前人已经给我们提出来了另外一个理论,就是BASE理论,它是用来对CAP定理进行进一步扩充的。BASE理论指的是:

  • Basically Available(基本可用)

  • Soft state(软状态)

  • Eventually consistent(最终一致性)

BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

3.3、常见解决方案

现阶段分布式事务有很多种解决方案,这里介绍几种常用的事务

A、TCC补偿式事务(try-confirm-cancel)

      一、 Try 阶段主要是对业务系统做检测及资源预留

      二、Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。

      三、Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

        举个例子,假入 A 要向 B 转账,思路大概是:
         我们有一个本地方法,里面依次调用
        1、首先在 Try 阶段,要先调用远程接口把 A 和 B 的钱给冻结起来。
        2、在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。
        3、如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

        缺点:1、一致性较差;2、confirm和cancel都有可能失败;3、业务较为复杂,回滚和提交处理不好会造成资源死锁

B、2PC/3PC方式

        一、2PC

        实现分布式事务的关键就是两阶段提交协议。在此协议中,一个或多个资源管理器的活动均由一个称为事务协调器的单独软件组件来控制。此协议中的五个步骤如下:

  • 应用程序调用事务协调器中的提交方法。

  •  事务协调器将联络事务中涉及的每个资源管理器,并通知它们准备提交事务(这是第一阶段的开始)。

  •  为 了以肯定的方式响应准备阶段,资源管理器必须将自己置于以下状态:确保能在被要求提交事务时提交事务,或在被要求回滚事务时回滚事务。大多数资源管理器会 将包含其计划更改的日记文件(或等效文件)写入持久存储区中。如果资源管理器无法准备事务,它会以一个否定响应来回应事务协调器。

  •  事务协调器收集来自资源管理器的所有响应。

  •  在 第二阶段,事务协调器将事务的结果通知给每个资源管理器。如果任一资源管理器做出否定响应,则事务协调器会将一个回滚命令发送给事务中涉及的所有资源管理 器。如果资源管理器都做出肯定响应,则事务协调器会指示所有的资源管理器提交事务。一旦通知资源管理器提交,此后的事务就不能失败了。通过以肯定的方式响 应第一阶段,每个资源管理器均已确保,如果以后通知它提交事务,则事务不会失败。

目前部分主流关系型数据库已经支持2PC,别名 XA Transactions。MySQL从5.5版本开始支持,SQL Server 2005 开始支持,Oracle 7 开始支持。

缺点:2pc协议在协调者和执行者同时宕机时(协调者和执行者不同时宕机时,都能确定事务状态),选出协调者之后 无法确定事务状态,会等待宕机者恢复才会继续执行(无法利用定时器来做超时处理,超时后也不知道事务状态,无法处理,强制处理会导致数据不一致),这段时间这个事务是阻塞的,其占用的资源不会被释放。

    二、3PC

        为了解决2PC事务阻塞这个问题,产生了3PC协议。

       3PC增加了一个中间状态,方便判断事务状态,新的协调者不用等宕机者恢复 就能决定事务状态,准确的提交事务或者终止事务。

  • CanCommit(能否提交)

  • PreCommit(预提交) 进入这个状态,说明各执行节点的状态都是canCommit

  • doCommit(预提交) 进入这个状态,说明个执行节点的状态都是precommit
    新协调者如果发现有的存活节点的状态是preCommit或doCommit,说明各执行节点的状态肯定都是"可以提交",协调者直接提交事务,能保证数据一致性 。
    如果发现有的存活节点状态是abort状态,说明事务被中断了,协调者继续中断事务就行。
    如果发现所有节点都是canCommit,说明各执行节点不会有处于doCommit状态(因为如果有节点是canCommit,不会有节点是canCommit状态),协调者中断事务,能保证数据一致性。

缺点:3pc解决了事务状态不可知的问题。不过其对执行者引入超时机制(超时后根据执行器当前状态canCommit or preCommit回滚或者提交事务,释放事务占用的资源),如果发生网络分区,会导致事务数据不一致,虽然提升了系统可用性,不过牺牲了系统一致性。