常见一致性协议(一)

这是Zookeeper学习总结 的系列文章。

在上一节的理论基础部分也提到,一个分布式系统往往是在可用性与一致性之间平衡。大多都是在保证一致性的前提下,尽可能地提高系统的整体可用性。常见的有二阶段提交(2PC)、三阶段提交(3PC)、Paxos、Raft等算法,在本文将介绍他们中的一部分。

2PC

2PC即Two-Phase Commit,二阶段提交。广泛应用在数据库领域,为了使得基于分布式架构的所有节点可以在进行事务处理时能够保持原子性和一致性。绝大部分关系型数据库,都是基于2PC完成分布式的事务处理。
顾名思义,2PC分为两个阶段处理,

事务提交示意图
事务中断示意图

阶段一:提交事务请求

  1. 事务询问。协调者向所有参与者发送事务内容,询问是否可以执行提交操作,并开始等待各参与者进行响应;
  2. 执行事务。各参与者节点,执行事务操作,并将Undo和Redo操作计入本机事务日志;
  3. 各参与者向协调者反馈事务问询的响应。成功执行返回Yes,否则返回No。

阶段二:执行事务提交

协调者在阶段二决定是否最终执行事务提交操作。这一阶段包含两种情形:

执行事务提交
所有参与者reply Yes,那么执行事务提交。

  1. 发送提交请求。协调者向所有参与者发送Commit请求;
  2. 事务提交。参与者收到Commit请求后,会正式执行事务提交操作,并在完成提交操作之后,释放在整个事务执行期间占用的资源;
  3. 反馈事务提交结果。参与者在完成事务提交后,写协调者发送Ack消息确认;
  4. 完成事务。协调者在收到所有参与者的Ack后,完成事务。

中断事务
事情总会出现意外,当存在某一参与者向协调者发送No响应,或者等待超时。协调者只要无法收到所有参与者的Yes响应,就会中断事务。

  1. 发送回滚请求。协调者向所有参与者发送Rollback请求;
  2. 回滚。参与者收到请求后,利用本机Undo信息,执行Rollback操作。并在回滚结束后释放该事务所占用的系统资源;
  3. 反馈回滚结果。参与者在完成回滚操作后,向协调者发送Ack消息;
  4. 中断事务。协调者收到所有参与者的回滚Ack消息后,完成事务中断。

2PC具有明显的优缺点:
优点主要体现在实现原理简单;
缺点比较多:

  • 2PC的提交在执行过程中,所有参与事务操作的逻辑都处于阻塞状态,也就是说,各个参与者都在等待其他参与者响应,无法进行其他操作;
  • 协调者是个单点,一旦出现问题,其他参与者将无法释放事务资源,也无法完成事务操作;
  • 数据不一致。当执行事务提交过程中,如果协调者向所有参与者发送Commit请求后,发生局部网络异常或者协调者在尚未发送完Commit请求,即出现崩溃,最终导致只有部分参与者收到、执行请求。于是整个系统将会出现数据不一致的情形;
  • 保守。2PC没有完善的容错机制,当参与者出现故障时,协调者无法快速得知这一失败,只能严格依赖超时设置来决定是否进一步的执行提交还是中断事务。

3PC

针对2PC的缺点,研究者提出了3PC,即Three-Phase Commit。作为2PC的改进版,3PC将原有的两阶段过程,重新划分为CanCommit、PreCommit和do Commit三个阶段。
三阶段提交示意图

阶段一:CanCommit

  1. 事务询问。协调者向所有参与者发送包含事务内容的canCommit的请求,询问是否可以执行事务提交,并等待应答;
  2. 各参与者反馈事务询问。正常情况下,如果参与者认为可以顺利执行事务,则返回Yes,否则返回No。

阶段二:

在本阶段,协调者会根据上一阶段的反馈情况来决定是否可以执行事务的PreCommit操作。有以下两种可能:

执行事务预提交

  1. 发送预提交请求。协调者向所有节点发出PreCommit请求,并进入prepared阶段;
  2. 事务预提交。参与者收到PreCommit请求后,会执行事务操作,并将Undo和Redo日志写入本机事务日志;
  3. 各参与者成功执行事务操作,同时将反馈以Ack响应形式发送给协调者,同事等待最终的Commit或Abort指令。

中断事务
加入任意一个参与者向协调者发送No响应,或者等待超时,协调者在没有得到所有参与者响应时,即可以中断事务:

  1. 发送中断请求。 协调者向所有参与者发送Abort请求;
  2. 中断事务。无论是收到协调者的Abort请求,还是等待协调者请求过程中出现超时,参与者都会中断事务;

阶段三:doCommit

在这个阶段,会真正的进行事务提交,同样存在两种可能。

执行提交

  1. 发送提交请求。假如协调者收到了所有参与者的Ack响应,那么将从预提交转换到提交状态,并向所有参与者,发送doCommit请求;
  2. 事务提交。参与者收到doCommit请求后,会正式执行事务提交操作,并在完成提交操作后释放占用资源;
  3. 反馈事务提交结果。参与者将在完成事务提交后,向协调者发送Ack消息;
  4. 完成事务。协调者接收到所有参与者的Ack消息后,完成事务。

中断事务
在该阶段,假设正常状态的协调者接收到任一个参与者发送的No响应,或在超时时间内,仍旧没收到反馈消息,就会中断事务:

  1. 发送中断请求。协调者向所有的参与者发送abort请求;
  2. 事务回滚。参与者收到abort请求后,会利用阶段二中的Undo消息执行事务回滚,并在完成回滚后释放占用资源;
  3. 反馈事务回滚结果。参与者在完成回滚后向协调者发送Ack消息;
  4. 中端事务。协调者接收到所有参与者反馈的Ack消息后,完成事务中断。

3PC的优缺点
3PC有效降低了2PC带来的参与者阻塞范围,并且能够在出现单点故障后继续达成一致;
但3PC带来了新的问题,在参与者收到preCommit消息后,如果网络出现分区,协调者和参与者无法进行后续的通信,这种情况下,参与者在等待超时后,依旧会执行事务提交,这样会导致数据的不一致。

原文地址:https://www.cnblogs.com/jenkov/p/distribute_sys_protocols_0.html