zdq0394.github.com

Tech study and research.

Follow me on GitHub

两阶段提交协议

两阶段提交协议是协调所有分布式原子事务参与者,并决定提交或取消(回滚)的分布式算法。

协议参与者

在两阶段提交协议中,系统一般包含两类节点:

  • 事务协调者(coordinator),通常一个系统中只有一个。
  • 事务参与者(participants,cohorts或workers),一般包含多个,在数据存储系统中可以理解为数据副本的个数

协议做了以下假设:

  • 每个节点都会记录写前日志(write-ahead log)并持久性存储即使节点发生故障日志也不会丢失
  • 节点不会发生永久性故障而且任意两个节点都可以互相通信

两个阶段的执行

请求阶段

请求阶段(commit-request phase),又称表决阶段(voting phase)。 在请求阶段,协调者将通知事务参与者准备提交或取消事务,然后进入表决过程。 在表决过程中,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)。

提交阶段(commit phase)

在该阶段,协调者将基于第一个阶段的投票结果进行决策:提交或取消 当且仅当所有的参与者同意提交事务,协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。 参与者在接收到协调者发来的消息后将执行相应的操作。

两阶段提交的缺点

  • 同步阻塞问题: 执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  • 单点故障: 由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去,尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)。
  • 数据不一致: 在两阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这会导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。

两阶段提交无法解决的问题

当协调者出错,同时参与者也出错时,两阶段无法保证事务执行的完整性。 考虑协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。 那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。