分布式事务

内容来自

  1. 极客时间专栏:《分布式技术原理与算法解析》
  2. 再有人问你分布式事务,把这篇扔给他
  3. 对分布式事务及两阶段提交、三阶段提交的理解

事务,其实是包含一系列操作的、一个有边界的工作序列,有明确的开始和结束标志,且要么被完全执行,要么完全失败回滚。而分布式事务,就是在分布式系统中运行的事务,由多个本地事务组合而成

事务的基本特征ACID

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

CAP和BASE理论

CAP

  • Consistency (一致性):对某个指定的客户端来说,读操作能返回最新的写操作。对于数据分布在不同节点上的数据上来说,如果在某个节点更新了数据,那么在其他节点如果都能读取到这个最新的数据,那么就称为强一致,如果有某个节点没有读取到,那就是分布式不一致。
  • Availability (可用性):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。可用性的两个关键一个是合理的时间,一个是合理的响应。合理的时间指的是请求不能无限被阻塞,应该在合理的时间给出返回。合理的响应指的是系统应该明确返回结果并且结果是正确的,这里的正确指的是比如应该返回50,而不是返回40。
  • Partition tolerance (分区容错性):当出现网络分区后,系统能够继续工作。打个比方,这里个集群有多台机器,有台机器网络出现了问题,但是这个集群仍然可以正常工作

CAP理论告诉我们:一个分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)、分区容错性(P:Partition tolerance)这三个基本需求,并且最多只能满足其中的两项,参考链接:

BASE

BASE 理论包括基本可用(Basically Available)软状态(Soft State)最终一致性(Eventual Consistency)

  • 基本可用:分布式系统出现故障的时候,允许损失一部分功能的可用性。比如,某些电商 618 大促的时候,会对一些非核心链路的功能进行降级处理。
  • 软状态:在柔性事务中,允许系统存在中间状态,且这个中间状态不会影响系统整体可用性。比如,数据库读写分离,写库同步到读库(主库同步到从库)会有一个延时,其实就是一种柔性状态。
  • 最终一致性:事务在操作过程中可能会由于同步延迟等问题导致不一致,但最终状态下,数据都是一致的

BASE解决了CAP中理论没有网络延迟,在BASE中用软状态和最终一致,保证了延迟后的一致性。BASE和 ACID 是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态

实现分布式事务的方法

  1. 基于 XA 协议的二阶段提交协议方法;
  2. 三阶段提交协议方法;
  3. TCC事务机制
  4. 本地消息表
  5. Saga事务

其中,基于 XA 协议的二阶段提交协议方法和三阶段提交协议方法,采用了强一致性,遵从 ACID,基于消息的最终一致性方法,采用了最终一致性,遵从 BASE 理论

1、基于 XA 协议的二阶段提交方法(2PC)

XA 实现分布式事务的原理,类似于分布式互斥中的集中式算法,由事务管理器作为协调者,负责各个本地资源的提交和回滚

流程

image.png

第一阶段:事务管理器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交.

第二阶段:事务协调器要求每个数据库提交数据,或者回滚数据

缺点分析

  • 同步阻塞问题:二阶段提交算法在执行过程中,所有参与节点都是事务阻塞型的。也就是说,当本地资源管理器占有临界资源时,其他资源管理器如果要访问同一临界资源,会处于阻塞状态。
  • 单点故障问题:基于 XA 的二阶段提交算法类似于集中式算法,一旦事务管理器发生故障,整个系统都处于停滞状态。尤其是在提交阶段,一旦事务管理器发生故障,资源管理器会由于等待管理器的消息,而一直锁定事务资源,导致整个系统被阻塞。
  • 数据不一致问题:在提交阶段,当协调者向参与者发送 DoCommit 请求之后,如果发生了局部网络异常,或者在发送提交请求的过程中协调者发生了故障,就会导致只有一部分参与者接收到了提交请求并执行提交操作,但其他未接到提交请求的那部分参与者则无法执行事务提交。于是整个分布式系统便出现了数据不一致的问题

2、三阶段提交协议方法(3PC)

三阶段提交协议(Three-phase commit protocol,3PC),是对二阶段提交(2PC)的改进,三阶段提交引入了超时机制和准备阶段:

  • 超时机制: 如果协调者或参与者在规定的时间内没有接收到来自其他节点的响应,就会根据当前的状态选择提交或者终止整个事务
  • 准备阶段: 也就是在提交阶段之前,加入了一个预提交阶段。在预提交阶段排除一些不一致的情况,保证在最后提交之前各参与节点的状态是一致的

流程

3PC 把 2PC 的提交阶段一分为二,这样三阶段提交协议就有 CanCommit、PreCommit、DoCommit 三个阶段
image.png

  • CanCommit:
    CanCommit 阶段与 2PC 的投票阶段类似:协调者向参与者发送请求操作(CanCommit 请求),询问参与者是否可以执行事务提交操作,然后等待参与者的响应;参与者收到 CanCommit 请求之后,回复 Yes,表示可以顺利执行事务;否则回复 No

  • PreCommit: 协调者根据参与者的回复情况,来决定是否可以进行 PreCommit 操作

    1. 如果所有参与者回复的都是“Yes”,那么协调者就会执行事务的预执行
    2. 假如任何一个参与者向协调者发送了“No”消息,或者等待超时之后,协调者都没有收到参与者的响应,就执行中断事务的操作
  • DoCommit: DoCmmit 阶段进行真正的事务提交,根据 PreCommit 阶段协调者发送的消息,进入执行提交阶段或事务中断阶段

和 2PC 的对比

  • 相比较2PC而言,3PC对于协调者和参与者都设置了超时时间,而2PC只有协调者才拥有超时机制。避免了参与者在长时间无法与协调者节点通讯(协调者挂掉了)的情况下,无法释放资源的问题,因为参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围
  • 在2PC的准备阶段和提交阶段之间,多设置了一个预提交阶段(PreCommit), 相当于加了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的

3、TCC事务机制

TCC(Try-Confirm-Cancel)又称补偿事务。其核心思想是:”针对每个操作都要注册一个与其对应的确认和补偿(撤销操作)”。它分为三个操作:

  • Try阶段:主要是对业务系统做检测及资源预留。
  • Confirm阶段:确认执行业务操作。
  • Cancel阶段:取消执行业务操作

image.png

适用场景

  • 强隔离性,严格一致性要求的活动业务
  • 执行时间较短的业务

4、本地消息表

在 eBay 的分布式系统架构中,解决一致性问题的核心思想就是:将需要分布式处理的事务通过消息或者日志的方式异步执行,消息或日志可以存到本地文件、数据库或消息队列中,再通过业务规则进行失败重试。
参考:Base: An Acid Alternative

5、Saga事务

Saga是30年前一篇数据库伦理提到的一个概念。其核心思想是将长事务拆分为多个本地短事务,由Saga事务协调器协调,如果正常结束那就正常完成,如果某个步骤失败,则根据相反顺序一次调用补偿操作

要注意的是,在saga模式中不能保证隔离性,因为没有锁住资源,其他事务依然可以覆盖或者影响当前事务,可以参照华为的解决方案:从业务层面入手加入一 Session 以及锁的机制来保证能够串行化操作资源。也可以在业务层面通过预先冻结资金的方式隔离这部分资源, 最后在业务操作的过程中可以通过及时读取当前状态的方式获取到最新的更新

具体实例:可以参考华为的servicecomb

拓展

刚性事务与柔性事务

  • 刚性事务,遵循 ACID 原则,具有强一致性。比如,数据库事务。
  • 柔性事务,其实就是根据不同的业务场景使用不同的方法实现最终一致性,也就是说我们可以根据业务的特性做部分取舍,容忍一定时间内的数据不一致。

总结来讲,与刚性事务不同,柔性事务允许一定时间内,不同节点的数据不一致,但要求最终一致。而柔性事务的最终一致性,遵循的是 BASE 理论

分布式互斥与分布式事务之间的关系