Skip to content

分布式事务

1、什么是分布式事务

分布式事务表示事务的参与者,事务所在的服务器,以及涉及的资源服务器,事务管理器等分别位于不同的服务或者不同的数据库节点上。

更简单的理解,事务表示一组操作,那么这一组操作中,包含多个操作 那么这多个操作可能存在不同的服务器上 或者多个操作根本就不属于同一个应用,分布式事务就表示,可能不在同一台服务器,不是同一个项目中的事务,整体成功或者整体失败。

1、事务

由一组操作构成的可靠、独立的工作单元,事务具备 ACID 的特性,即原子性、一致性、隔离性和持久性。

2、本地事务

本地事务由本地资源管理器(通常指数据库管理系统 DBMS,例如 MySQL、Oracle 等)管理,严格地支持 ACID 特性,高效可靠。本地事务不具备分布式事务的处理能力,隔离的最小单位受限于资源管理器,即本地事务只能对自己数据库的操作进行控制,对于其他数据库的操作则无能为力。

3、全局事务

全局事务指的是一次性操作多个资源管理器完成的事务,由一组分支事务组成。

4、分支事务

在分布式事务中,就是一个个受全局事务管辖和协调的本地事务。

我们可以将分布式事务理解成 一个包含了若干个分支事务的全局事务

全局事务的职责是协调其管辖的各个分支事务达成一致,要么一起成功提交,要么一起失败回滚。

此外,通常分支事务本身就是一个满足 ACID 特性的本地事务。

2、CAP理论

CAP 理论(有时也被称为布鲁尔定理(Brewer's Theorem))是分布式系统设计中的一个重要理论,它由计算机科学家 Eric Brewer 在 2000 年提出,用来描述分布式系统中的三个基本特性:一致性(Consistency)可用性(Availability)分区容错性(Partition Tolerance)

  1. 一致性(Consistency):
    • 一致性要求在分布式系统中的所有节点上,对数据的访问都呈现一致的视图。即,无论客户端访问哪个节点,都能够获得相同的数据。在一致性的情况下,系统的所有节点在同一时间点的数据状态是相同的。
    • 比如: mysql的主从复制读写分离时,当对主库添加数据成功时,从库必须也添加成功 并且从从库中读取数据时读取的应该是最新的数据,不能出现主库添加数据后从从库中读取的不是最新的数据,比如在主从复制过程中读取从库,此时数据还没有复制过来,此时读取的可能就不是最新的数据,此时就不满足一致性了所以想要满足一致性,当主库添加数据时,需要把数据同步到从库 并且同步的时候需要锁定从库,不能让从库参与读取,等到同步完成之后再取消锁定,此时再读就是最新的数据了,此时就满足了一致性。
  2. 可用性(Availability):
    • 可用性要求系统在任何时候都能够对外提供服务,即使系统中的一些节点出现故障。即,对于客户端的请求,系统能够在合理的时间内返回结果,而不是出现无响应或错误。
    • 比如:mysql的读写分离,当对主机添加数据时,从机会复制这条数据,当客户端读取从机时 不能超时报错必须得有响应。此时允许读取的数据不是最新的。从机还不能被锁定。
  3. 分区容错性(Partition Tolerance):
    • 分区容错性是指系统能够在节点之间发生通信故障或分区的情况下继续工作。
    • 比如:mysql的读写分离,给主机添加一条数据时,主机应该异步把数据复制给从机, 不能同步复制给从机,如果同步复制给从机,导致主机线程阻塞,影响用户二次插入(影响了主机对外提供添加数据服务),并且从机不能只有一个要有多个,如果只有一个从机,从机挂了之后影响了读操作(影响了从机对外提供读取数据服务),如果有多个从机,其中一个从机挂了 其他的从机还会对外提供服务保证系统了正常运行。

CAP定理证明 在分布式系统中要么满足CP ,要么满足AP,无法满足CA,更无法满足CAP

  • 无法满足CA的原因
    • 因为一致性要求数据必须一致,要想一致得锁定,锁定后则无法被访问,可用性又强调不能超时,还快速响应非错误结果,数据可以不一致,很显然矛盾的。
  • 可以满足CP的原因
    • C表示一致性,P表示分区容错性,如果考虑网络分区的情况下,当给主库添加数据时,主库把数据同步给从库此时主库线程等待,直到把数据全部同步给网络分区中的所有的从机,这就不满足有快速响应结果的可用性了所以不能有A。
  • 可以满足AP的原因
    • A表示可用性,访问需要快速响应,P表示分区容错性,挂机不影响对外提供服务,就要保证请求时快速从网络分,区节点中响应数据,此时就有可能从不同的节点中读取的数据不同,不满足一致性所以不能有C。
  • 实际中的考虑
    • 一般的系统中会优先使用AP,不强调强一致性,允许数据在某一个时间点不一致,但是数据经过一段时间间隔最终会一致。
    • 对一致性要求比较高的系统可能会选择CP,强调强一致性,比如银行,银行可能要求,不论什么时候查询,都要查询到最新的数据。

3、分布式事务解决方案

  • 强一致性 CP
    • XA协议 数据库级别的规范,需要数据库的支持
  • 弱一致性 AP
    • TCC
    • AT
    • Saga
    • 可靠消息最终一致性
    • 最大努力通知 xxl-job + MQ 定时轮询

XA协议:

  • 说明: XA是一种分布式事务协议,涉及多个数据库。它要求每个涉及的数据库都要支持事务,并且由一个事务管理器协调和控制事务的提交和回滚。
  • 优点: 提供了强一致性,所有参与的数据库要么都提交,要么都回滚。
  • 缺点: 实现复杂,性能开销较大。

TCC(Try-Confirm-Cancel):

  • 说明: TCC是一种基于补偿机制的分布式事务解决方案。每个操作被分解成三个阶段:尝试执行、确认执行和取消执行。通过事务的回滚和补偿操作来实现最终一致性。
  • 优点: 灵活性高,可以自定义补偿逻辑。
  • 缺点: 业务逻辑的改造较大,需要开发者定义补偿逻辑。

AT(Two-Phase Commit):

  • 说明: AT是一种两阶段提交协议,通过协调者向参与者发送两个消息(准备阶段和提交/回滚阶段)来实现事务的一致性。
  • 优点: 相对XA来说实现相对简单。
  • 缺点: 存在单点故障,可能导致协调者故障时系统无法正常运作。

Saga:

  • 说明: Saga是一种流程型的分布式事务解决方案,将大事务拆分成多个小事务,每个小事务有自己的补偿操作。通过事务的步骤序列和补偿来实现最终一致性。
  • 优点: 可以实现较为复杂的业务流程。
  • 缺点: 需要开发者定义补偿逻辑,系统复杂度相对较高。

可靠消息最终一致性:

  • 说明: 通过消息队列,将事务操作转换为消息发送,保证消息的可靠性投递,接收方异步处理消息。消息队列通常提供至少一次投递保证,确保消息最终被消费。
  • 优点: 简单易实现,可靠性较高。
  • 缺点: 无法处理所有可能的一致性问题,依赖于消息队列的可靠性。

最大努力通知:

  • 说明: 在分布式系统中,发送通知的一方尽最大努力发送通知,但不能保证通知的可靠性。接收通知的一方需要实现幂等性来处理可能的重复通知。
  • 优点: 简单,适用于不强调强一致性的场景。
  • 缺点: 不能保证通知的可靠性,需要接收方处理幂等性问题。

4、两阶段提交模型

二阶段提交表示的是XA规范下的事务提交 分为2个阶段

第一个阶段: 资源服务器执行xa prepare。

1、事务管理器通知资源管理器,让资源管理器为提交事务做准备

2、资源管理器收到消息后 执行sql 执行本地事务执行完毕之后不会提交事务,向事务管理器说我执行sql没有出现问题,已经准备好了提交(注意当前资源管理器当前线程阻塞,等待提交)

第二个阶段: 1、如果各个资源管理器都执行成功 则向各个资源管理器发送提交事务的请求

2、各个资源管理器收到请求之后 执行本地事务提交 然后释放资源

异常情况:

1、如果有资源管理器返回的是失败 则向各个资源管理器发送回滚事务的请求

2、各个资源管理器收到请求之后 执行事务回滚 然后释放资源

image-20240119095023476

image-20240119095036538

可能出现数据不一致 当所有参与者操作执行完成,并且向协调者发回同意的消息之后,协调者就会向所有的参与者发出提交的请求,假设者提交请求发到了参与者1,参与者2,但当发送给参与者3时,发生了网络异常,提交请求并没有到达参与者3,就会出现参与者1,参与者2都提交了,参与者3却没有提交,这个时候,整个分布式系统中就会出现数据不一致的情况。

5、三阶段提交模型

因为二阶段提交出现了问题,所以在二阶段的基础上,提出了三阶段提交。

三阶段提交时二阶段提交的改进版本,三个阶段如下:

预备阶段、准备阶段、提交阶段

预备阶段、准备阶段是从二阶段准备阶段拆分出来的

在三阶段中,也是一个协调者和多个参与者 参与者1,2,3

具体逻辑实现

1.预备阶段

协调者开启事务,向参与者发出询问的请求,询问参与者是否可以执行分布式事务的请求,可以执行就会返回一个同意的消息,如果不可以执行就会返回一个中止的消息,在协调者收到所有参与者的询问相应之后,分布式事务就进入了第二个阶段——准备阶段。

2.准备阶段

假设所有的参与者返回的是同意消息,那么分布式事务开始执行,协调者会向所有参与者发出执行分布式事务的请求,在所有参与者收到请求之后,会将所有的分布式事务记录成日志,然后逐条执行分布式事务操作,执行完之后,先不提交,如果执行成功,就返回一个同意的消息,如果执行本地事务的过程中,出现了异常,返回中止消息,在所有参与者返回本地执行结果之后,分布式事务进入第三个阶段,提交阶段。

3.提交阶段

协调者会根据所有参与者返回的结果来确定下一步的操作

假设所有参与者返回的都是同意的消息,那么协调者就知道所有的参与者准备好了,也就会开始执行提交请求,在参与者收到提交请求之后,就会执行本地事务的提交,并且释放相应的资源,执行完成之后,再返回一个完成的消息,在协调者收到所有的完成消息之后,分布式事务也就执行成功了。这是执行正常的情况。

异常处理

1.在预备阶段,协调者询问参与者是否进行分布式事务时,参与者并没有准备好,参与者会返回一个中止消息。

2.在准备阶段,参与者在执行本地事务时,执行异常,那么返回的不是同意,而是中止消息。

无论是第一种情况,还是第二种情况,一旦协调者收到参与者中止消息,就会中止分布式事务,向所有的参与者发出回滚的请求,参与者在收到回滚请求后,会根据日志,将所有的请求撤销,回到分布式事务开启之前的一致状态,这样,整个分布式事务就执行失败。

三阶段提交相对于二阶段提交的改进:

在三阶段提交增加了预备阶段,一旦进入预备阶段,表示所有参与者已经准备好分布式事务,即所有参与者的本地事务是可以执行成功的,这个时候,如果参与者记录完日志,并且执行完本地事务操作之后,就差提交了,这个时候不管发生协调者异常还是网络异常,协调者提交之后,请求没有到达参与者,参与者在等待超时之后,都会默认提交分布式事务,相对于二阶段提交,若二阶段异常,是没办法继续执行的,所以三阶段提交的改进是在二阶段提交没办法继续执行的情况下,可默认将事务提交。

缺点:

当参与者1执行本地事务异常时,给协调者回复中止信号,恰好协调者也异常,这个时候协调者无法中止整个分布式事务,参与者2,参与者3的事务会默认提交,但是参与者1又是执行异常的情况,整个分布式系统也会不一致,所以三阶段提交虽然改变了二阶段提交的问题,但并没有完美实现分布式事务,不过,理论上如此,在具体的实现中,我们会根据业务,对数据进行补偿和修正,以保证业务的数据最终一致。