zl程序教程

您现在的位置是:首页 >  其他

当前栏目

# 分布式理论协议与算法 第二弹 ACID原则

2023-02-19 12:21:06 时间

ACID 原则是在 1970年 被 Jim Gray 定义,用以表示事务操作:一个事务是指对数据库状态进行改变的一系列操作变成一个单个序列逻辑元操作,数据库一般在启动时会提供事务机制,包括事务启动 停止 取消或回滚。 但是上述事务机制并不真的实现“事务”,一个真正事务应该遵循 ACID 属性,ACID 事务才真正解决事务,包括并发用户访问同一个数据表记录的头疼问题。ACID事务解决了很多问题,但是仍然需要和性能做平衡协调,事务越强,性能可能越低,安全可靠性和高性能是一对矛盾。 本篇内容主要包括:ACID 理论概述、2PC 协议、3PC 协议


文章目录


一、ACID 理论概述

1、ACID 简介

ACID 原则是在 1970年 被 Jim Gray 定义,用以表示事务操作:一个事务是指对数据库状态进行改变的一系列操作变成一个单个序列逻辑元操作,数据库一般在启动时会提供事务机制,包括事务启动 停止 取消或回滚。

但是上述事务机制并不真的实现“事务”,一个真正事务应该遵循 ACID 属性,ACID 事务才真正解决事务,包括并发用户访问同一个数据表记录的头疼问题。ACID事务解决了很多问题,但是仍然需要和性能做平衡协调,事务越强,性能可能越低,安全可靠性和高性能是一对矛盾。

2、ACID 定义

ACID 可以理解为 ACID 最重要的含义,就是 Atomicity 和 Isolation ,即强制一致性,要么全做要么不做,所有用户看到的数据一致。强调数据的可靠性, 一致性和可用性。

ACID 为 Atomicity、Consistency、Isolation and Durability,其中 ACID 分别表示为:

  • 原子性(Atomicity):事务中的操作要么都做,要么都不做。
  • 一致性(Consistency):系统必须始终处在强一致状态下。
  • 隔离性(Isolation):一个事务的执行不能被其他事务所干扰。
  • 持续性(Durability):一个已提交的事务对数据库中数据的改变是永久性的。

保证 ACID 是传统关系型数据库中事务管理的重要任务,几种事务类型为:未提交读、可提交读、可重复读、可序列化。

3、CAP 和 ACID 一致性区别

ACID 一致性是有关数据库规则,如果数据表结构定义一个字段值是唯一的,那么一致性系统将解决所有操作中导致这个字段值非唯一性的情况,如果带有一个外键的一行记录被删除,那么其外键相关记录也应该被删除,这就是 ACID 一致性意思。

CAP 理论的一致性是保证同样一个数据在所有不同服务器上的拷贝都是相同的,这是一种逻辑保证,而不是物理,因为光速限制,在不同服务器上这种复制是需要时间的,集群通过阻止客户端查看不同节点上还未同步的数据维持逻辑视图。

当跨分布式系统提供 ACID 时,这两个概念会混淆在一起,Google’s Spanner system 能够提供分布式系统的ACID,其包含 ACID+CAP 设计:

4、分布式系统下 ACID 的协议

分布式系统下类比 ACID 的强一致性协议有 2PC、3PC、Paxos、Raft、Quorum NWR …


二、2PC 协议

1、2PC(两阶段提交)概述

在分布式系统中,每个节点虽然可以知晓自己的操作时成功或者失败,却无法知道其他节点的操作的结果。所以需要引入一个作为协调者,统一掌控所有节点(称作参与者)的操作结果,并决定最终结果。因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

所谓的两个阶段分别是:

  • 第一阶段:准备阶段(投票阶段)
  • 第二阶段:提交阶段(执行阶段)

2、第一阶段:提交事务请求

事务管理器给每个参与者发送Prepare消息,每个数据库参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。 (Undo日志是记录修改前的数据,用于数据库回滚,Redo日志是记录修改后的数据,用于提交事务后写入数据文件)

3、第二阶段:事务执行

如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息; 参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。

4、2PC 主要缺点

  1. 同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  2. 单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
  3. 数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送 commit 请求过程中,网络异常或者协调者发生了故障,导致只有一部分参与者接受到了 commit 请求。于是整个分布式系统便出现了数据不一致的现象。
  4. 参与者故障时,协调者只能靠超时操作中断事务,容错性差,一个节点失败,整个事务就失败了。

三、3PC 协议

三段提交(3PC)是对两段提交(2PC)的一种升级优化,主要是为了解决两阶段提交协议的阻塞问题,2PC 存在的问题是当协作者崩溃时,参与者不能做出最后的选择。因此参与者可能在协作者恢复之前保持阻塞。三阶段提交(Three-phase commit),是二阶段提交(2PC)的改进版本。

1、改动点

与两阶段提交不同的是,三阶段提交有两个改动点。

  1. 把二段提交的第一个段分成了两段:询问,然后再锁资源,在询问的时候并不锁定资源,除非所有人都同意了,才开始锁资源。保证了在最后提交阶段之前,各参与者节点的状态都一致。
  2. 在参与者中也引入超时机制。 当参与者各种原因未收到协调者的 commit 请求后,会对本地事务进行 commit,不会一直阻塞等待,解决了 2PC 的单点故障问题。

但 3PC 还是没能从根本上解决数据一致性的问题。3PC 的三个阶段分别是 CanCommit、PreCommit、DoCommit。

2、第一阶段:CanCommit

  1. 协调者进行事务询问,协调者向所有的参与者发送一个包含事务内容的 CanCommit 请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应。
  2. 参与者向协调者反馈事务询问,参与者在接收到来自协调者的包含了事务内容的 CanCommit 请求后,正常情况下,如果自身认为可以顺利执行事务,则反馈 Yes 响应,并进入预备状态,否则反馈 No 响应。

3、第二阶段:PreCommit

协调者在得到所有参与者的响应之后,参与者在 CanCommit 反馈的是 Yes,执行事务预提交:

  1. 协调者发送预提交请求(发出 preCommit 请求,并进入 prepared 阶段)
  2. 参与者进行事务预提交(参与者接收到 preCommit 请求后,会执行事务操作,并将 Undo 和 Redo 信息记录到事务日志中。)
  3. 各参与者向协调者反馈事务执行的结果(若参与者成功执行了事务操作,那么反馈 Ack)

协调者在得到所有参与者的响应之后,参与者在 CanCommit 反馈的是 No**,**中断事务:

  1. 协调者发送中断请求:(协调者向所有参与者发出 abort 请求。)
  2. 中断事务(无论是收到来自协调者的 abort 请求或者等待协调者请求过程中超时,参与者都会中断事务)

4、第三阶段:DoCommit

DoCommit阶段完成真正的事务提交或者完成事务回滚。

在第二阶段 PreCommit 阶段收到ACK确认消息,则完成事务提交:

  1. 协调者发送提交 DoCommit 请求(协调者将从预提交状态转化为提交状态,并向所有的参与者发送 DoCommit 请求)
  2. 参与者进行事务提交(参与者接收到 DoCommit 请求后,会正式执行事务提交操作,并在完成提交之后释放整个事务执行过程中占用的事务资源。)
  3. 各参与者向协调者反馈事务提交的结果(若参与者成功完成事务提交,那么反馈 Ack 响应)
  4. 完成事务(协调者接收到所有参与者反馈的 Ack 消息后,完成事务。)

在第二阶段PreCommit阶段超时中断没有收到 ACK 确认消息,则完成事务中断:

  1. 协调者发送中断请求(协调者向所有的参与者节点发送 abort 请求)
  2. 参与者进行事务回滚(根据记录的 Undo 信息来执行事务回滚,并在完成回滚之后释放整个事务执行期间占用的资源)
  3. 各参与者向协调者反馈事务回滚的结果(参与者在完成事务回滚后,向协调者发送 Ack 消息。)
  4. 中断事务(协调者接收到所有参与者反馈的 Ack 消息后,中断事务。)

注意:在 DoCommit 阶段可能出现协调者宕机、协调者与参与者出现网络故障;导致参与者接收不到协调者的 DoCommit 请求或 Abort 请求, 参与者会在请求超时后,继续进行事务提交。

5、3PC 的优缺点

优点:相对于 2PC,3PC 主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit(因为理论上来说,如果第一阶段所有的结点返回成功,那么有理由相信成功提交的概率很大)。而不会一直持有事务资源并处于阻塞状态。

缺点:但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的中断响应没有及时被参与者接收到,那么参与者在等待超时之后执行了 commit 操作。这样就和其他接到 abort 命令并执行回滚的参与者之间存在数据不一致的情况。

总结:

  • 相比较 2PC 而言,3PC 对于协调者和参与者都设置了超时时间,而 2PC 只有协调者才拥有超时机制。这解决了一个什么问题呢?这个优化点主要是避免了参与者在长时间无法与协调者通讯的情况下(协调者挂掉了),无法释放资源阻塞的问题。
  • 但是相应的,正因为引入了参与者的超时机制,也导致了 3PC 协议在第二三阶段很容易出现数据不一致的问题。

简单来说 2PC 是一个数据强一致性协议,而 3PC 通过弱化数据的一致性来解决阻塞的问题。