ACID 原则与多阶段提交

ACID 原则

ACID,即 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)四种特性的缩写。

ACID 也是一种比较出名的描述一致性的原则,通常出现在分布式数据库等基于事务过程的系统中。

具体来说,ACID 原则描述了分布式数据库需要满足的一致性需求,同时允许付出可用性的代价。

  • Atomicity:每次事务是原子的,事务包含的所有操作要么全部成功,要么全部不执行。一旦有操作失败,则需要回退状态到执行事务之前;
  • Consistency:数据库的状态在事务执行前后的状态是一致的和完整的,无中间状态。即只能处于成功事务提交后的状态;
  • Isolation:各种事务可以并发执行,但彼此之间互相不影响。按照标准 SQL 规范,从弱到强可以分为未授权读取、授权读取、可重复读取和串行化四种隔离等级;
  • Durability:状态的改变是持久的,不会失效。一旦某个事务提交,则它造成的状态变更就是永久性的。

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

注:ACID 和 BASE 在英文中分别是“酸”和“碱”,看似对立,实则是对 CAP 三特性的不同取舍。

两阶段提交

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

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

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

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

  • 第一阶段时,各参与者同步阻塞等待时无法处理请求,会导致系统性较差;
  • 存在协调者单点故障问题,最坏情况下协调者总是在第二阶段故障,无法完成提交;
  • 可能产生数据不一致的情况。例如第二个阶段时,协调者将正式提交请求发给部分参与者后发生故障。

三阶段提交

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

完整过程如下:

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

三阶段提交主要解决了阻塞问题和协调者单点故障问题。第三阶段时,如果参与者无法及时收到协调者的消息,可以在超时后自动进行提交。但是当协调者发出的回滚消息未被部分参与者收到时,会出现不一致的情况。

其实,无论两阶段还是三阶段提交,都只是一定程度上缓解了提交冲突的问题,并无法确保系统的一致性。首个有效的共识算法是后来提出的 Paxos 算法。