> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/blockchain_guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/blockchain_guide/04_distributed_system/acid.md).

# ACID 原则与多阶段提交

## ACID 原则

ACID，即 Atomicity（原子性）、Consistency（一致性）、Isolation（隔离性）、Durability（持久性）四种特性的缩写。

ACID 是描述事务语义的原则，通常出现在数据库等基于事务过程的系统中。

具体来说，ACID 原则描述了事务在故障、并发和提交过程中的约束。这里的 Consistency 指数据库完整性约束和业务不变量，不等同于 CAP 中多个副本对外表现为单副本的原子一致性或线性一致性。

* Atomicity：每次事务是原子的，事务包含的所有操作要么全部成功，要么全部不执行。一旦有操作失败，则需要回退状态到执行事务之前；
* Consistency：事务如果从一个合法状态开始执行，提交后也必须让数据库处于合法状态，并满足约束、触发器、引用完整性和业务不变量；
* Isolation：各种事务可以并发执行，但彼此之间互相不影响。按照标准 SQL 规范，从弱到强可以分为未授权读取、授权读取、可重复读取和串行化四种隔离等级；
* Durability：状态的改变是持久的，不会失效。一旦某个事务提交，则它造成的状态变更就是永久性的。

与 ACID 相对的一个原则是 eBay 技术专家 Dan Pritchett 提出的 BASE（Basic Availability，Soft-state，Eventual Consistency）原则。BASE 原则面向大型高可用分布式系统，主张牺牲掉对强一致性的追求，而实现最终一致性，来换取一定的可用性。

*注：ACID 和 BASE 在英文中分别是“酸”和“碱”。两者常被放在 CAP 取舍中讨论，但 ACID 的一致性是事务合法性，CAP 的一致性是副本可见性，不能直接混用。*

## 两阶段提交

对于分布式事务一致性的研究成果包括著名的两阶段提交算法（Two-phase Commit，2PC）和三阶段提交算法（Three-phase Commit，3PC）。

两阶段提交算法最早由 Jim Gray 于 1979 年在论文《Notes on Database Operating Systems》中提出。其基本思想十分简单，既然在分布式场景下，直接提交事务可能出现各种故障和冲突，那么可将其分解为预提交和正式提交两个阶段，规避风险。

* 预提交（PreCommit）：协调者（Coordinator）发起执行某个事务的执行并等待结果。各参与者（Participant）执行事务但不提交，反馈是否能完成，并阻塞等待协调者指令；
* 正式提交（DoCommit）：协调者如果得到所有参与者的成功答复，则发出正式提交指令，否则发出状态回滚指令。

两阶段提交算法因为其简单容易实现的优点，在关系型数据库等系统中被广泛应用。当然，其缺点也很明显。

* 第一阶段时，各参与者同步阻塞等待时无法处理请求，会导致系统可用性较差；
* 存在协调者单点故障问题。参与者一旦投票同意提交，就必须等待协调者的提交或回滚决定；如果协调者在第二阶段故障，参与者会处于 in-doubt 状态并阻塞；
* 在具备持久日志和正确恢复机制时，两阶段提交的目标是保证原子提交，而不是允许数据不一致。真正的风险在于长时间阻塞；只有在日志丢失、人工启发式提交/回滚或实现错误时，才可能破坏原子性并造成不一致。

## 三阶段提交

三阶段提交算法针对两阶段提交算法第一阶段中参与者阻塞问题进行了优化。具体来说，将预提交阶段进一步拆成两个步骤：询问提交和预提交。

完整过程如下：

* 询问提交（CanCommit）：协调者询问参与者是否能进行某个事务的提交。参与者需要返回答复是否准备好，但无需执行提交，也无需阻塞。这就避免出现参与者被阻塞的情况；
* 预提交（PreCommit）：协调者检查收集到的答复，如果全部为真，则发起执行事务请求。各参与者（Participant）需要执行事务但不提交，并反馈能否完成。注意此时说明所有参与者都已经处于准备好状态；
* 正式提交（DoCommit）：协调者如果得到所有参与者的成功答复，则发出正式提交请求，否则发出状态回滚指令。本阶段时，如果参与者一直收不到请求，则超时后继续提交。

三阶段提交主要在有界延迟、故障可检测等更强假设下缓解两阶段提交的阻塞问题和协调者单点故障问题。第三阶段时，如果参与者无法及时收到协调者的消息，可以在超时后自动进行提交；但在异步网络或发生网络分区时，这类超时判断并不可靠，仍可能出现不同参与者做出不同决定的风险。

其实，两阶段提交解决的是分布式事务的原子提交问题，但在协调者故障时可能阻塞；三阶段提交用更强时序假设缓解阻塞。它们不同于 Paxos、Raft 等共识算法，后者通过多数派复制来在部分节点故障时继续对提交决定达成一致。
