谭浩的博客

Simple is beauty.

分布式系统 —— 事务ACID、2PC、3PC、2PL

ACID事务

传统的数据库系统依赖于将工作捆绑到具有 ACID 属性的事务中。如此,他们就通过牺牲可用性或者分区容忍性来保证一致性。ACID 是以下单词的缩写:

  • Atomicity “All or nothing”
  • Consistency 隐含着两种类型的一致性。单一系统的一致性以及跨系统的一致性。换句话说,如果从一个银行转出100元至另一个银行。不仅一个银行扣除了100,另一个银行也需要加上这100.
  • Isolation 无论并发级别如何,事务必须产生相同的结果就像一次只有一个事务执行一样(可以是任何一个可能的执行顺序)
  • Durability 持久性,即使崩溃了,已有数据依然存在

分布式事务和原子提交协议

通常情况下,事务将分布在多个系统上。如果数据库的多个副本必须保持统一, 则可能会出现这种情况。去实现事务我们需要保证分布式事务必须在所有的系统上有效或者在所有的系统上不执行。为了实现原子性,我们需要原子提交协议。

Two Phase Commit (2PC)

最常用的原子提交协议就是 2PC。两阶段提交让协调者更具参与者信息决定是否提交或放弃事务。

Three Phase Commit (3PC)

另一被用于现实生活中的提交协议是三阶段提交。该协议可以减少阻塞量, 并在发生故障时提供更灵活的恢复。尽管在异常失败易发的环境中,3PC 是更好的选择,但是它的复杂性让 2PC 成为了更受欢迎的选择。

协调者

协调者

参与者:

3PC中的恢复

如果参与者发现自己处于 Recovery 状态,它假定协调者没有响应。如果大多数参与者处于不确定和可提交的状态, 则可能会选出新的协调员并继续。一旦我们有了新的协调员, 它就会对参与者进行调查, 并采取相应行动:

  • 如果任何参与者已中止, 它将 Abort 发送给所有人 (此操作是强制性的-“All or nothing”)。
  • 如果任何参与者已提交, 它将 COMMIT 发送给所有人
  • 如果至少有一个参与者处于可提交的状态, 并且大多数参与者是可提交的或不确定的, 将 PRECOMMIT 发送给每个参与者, 并继续进行 “标准计划” 提交。
  • 如果没有可提交的参与者, 但超过一半是不确定的, 发送一个 PREABORT 给所有参与者。然后在一半以上的进程处于可中止状态时, 用一个 ABORT 指令跟进此操作。此操作是必需的, 因为中止是唯一的安全操作。
  • 如果以上所有都不为真,则阻塞直到有更多的响应可用。

Two Phase Locking (2PL)

在我们追求高吞吐量时,我们可能需要并行处理拥有共享资源的两个事务。这时就需要处理隔离性的问题。通常我们使用锁对资源进行访问,但是在并发获取锁的过程中极易出现死锁问题。为了解决死锁问题,我们可以让用户按照一定的顺序对资源加锁,因此不可能会出现事务等待获取一个比自己已拥有的资源更靠前顺序的资源,依赖链也就不可能出现环路。

以上正是两阶段锁的基础。在第一阶段,一个事务严格按照顺序获取所有的锁资源。然后使用资源。在最后的阶段,事务收缩和释放锁。由此就可以防止死锁。