《系统设计》课程学习笔记—事务

167 阅读5分钟

事务是一系列被视为“单一工作单元”的数据库操作。事务中的操作要么全部成功,要么全部失败。通过这种方式,事务的概念支持系统部分故障时的数据完整性。并非所有数据库都选择支持 ACID 事务,有时它们会优先考虑其他优化,这些优化很难或理论上不可能一起实现。

通常,关系数据库支持ACID事务,而非关系数据库不支持(也有例外)。

状态

数据库中的事务可以处于以下状态之一:

transaction-states.png

活跃状态(Active)

在此状态下,事务正在执行。这是每个事务的初始状态。

部分提交状态(Partially Committed)

当事务执行其最终操作时,它处于部分提交状态。

提交状态(Committed)

如果事务成功执行了所有操作,则称为提交。它的所有效果现在都永久保存在数据库系统中。

失败状态(Failed)

如果数据库恢复系统进行的任何检查失败,则事务将处于失败状态。失败的事务无法继续。

中止状态(Aborted)

如果有任何检查失败且事务已达到失败状态,则恢复管理器将回滚对数据库的所有写入操作,以使数据库恢复到执行事务之前的原始状态。事务此时的状态为中止。

数据库恢复模块可以在事务中止后选择以下两种操作之一:

  • 重新启动事务

  • 终止交易

结束状态(Terminated)

如果没有任何回滚或来自提交状态的事务,则系统当前一致并准备好处理新事务,旧事务结束。

分布式事务

分布式事务是跨两个或多个数据库对数据执行的一组操作。它通常在由网络连接的独立节点之间进行协调,但也可以跨单个服务器上的多个数据库。

为什么我们需要分布式事务?

与单个数据库上的 ACID 事务不同,分布式事务涉及更改多个数据库上的数据。分布式事务处理更加复杂,因为数据库必须作为一个独立单元协调事务中更改的提交或回滚。

换句话说,所有节点都必须提交,否则所有节点都将中止,整个事务将回滚。这就是为什么我们需要分布式事务。

现在,让我们看看一些流行的分布式事务解决方案:

两阶段提交

two-phase-commit.png

两阶段提交(2PC)协议是一种分布式算法,它协调参与分布式事务的所有进程,确定是否提交或中止(回滚)事务。

该协议在许多临时系统故障的场景下也能实现其目标,因此被广泛使用。然而,它并非对所有可能的故障配置都具有弹性,在极少数情况下,需要手动干预来改正结果。

该协议需要一个协调器来协调和监督不同节点之间的事务。协调器试图在两个阶段的一组进程中建立共识并因此得名。

阶段

两阶段提交包括以下阶段:

准备阶段

准备阶段涉及协调节点从每个参与者节点收集共识。事务在每个节点都响应准备就绪之前一直处于中止状态。

提交阶段

如果所有参与者都向协调器响应他们准备好了,那么协调器会要求所有节点提交事务。如果发生故障,事务将回滚。

问题

在两阶段提交协议中可能存在以下问题:

  • 如果其中一个节点崩溃怎么办?
  • 如果协调器本身崩溃怎么办?
  • 它是一个阻塞协议。

三阶段提交

three-phase-commit.png

三阶段提交(3PC)是两阶段提交的扩展,其中提交阶段分为两个阶段。这有助于解决两阶段提交协议中出现的阻塞问题。

阶段

三阶段提交包括以下阶段:

准备阶段

此阶段与两阶段提交相同。

提交前阶段

协调器发出预提交消息,所有参与者节点必须确认该消息。如果参与者未能及时收到此消息,则事务将中止。

提交阶段

此步骤也类似于两阶段提交协议。

什么提交前阶段有帮助?

预提交阶段完成以下工作:

  • 如果在此阶段中找到了参与者节点,则意味着每个参与者都完成了第一阶段。保证准备阶段的完成。

  • 每个阶段现在都可以超时,避免无限期等待。

Sagas

sagas.png

Saga 是一系列本地事务。每个本地事务更新数据库并发布消息或事件以触发 Saga 中的下一个本地事务。如果本地事务因违反业务规则而失败,则 Saga 将执行一系列补偿事务,以撤销先前本地事务所做的更改。

协作

有两种常见的实现方法:

  • 基于事件的方式(Choreography):每个本地事务发布触发其他服务中本地事务的域事件。
  • 基于命令的方式(Orchestration):由协调中心告诉参与者要执行哪些本地事务。

问题

  • Saga模式特别难以调试。
  • Saga参与者之间存在循环依赖的风险。
  • 缺少参与者数据隔离带来了持久性挑战。
  • 测试很困难,因为必须运行所有服务才能模拟事务。