分布式理论的两阶段和三阶段协议介绍

分布式领域两阶段(2PC)和三阶段(3PC)都是非常经典的概念,本文简单介绍下2PC和3PC的一些概念和优劣,做个记录。

两阶段提交

两阶段提交用来保持在分布式系统架构里的原子性和一致性,关于事务特性见前文,本文后面的PPT里也有简单补充。
其中包含的角色为:协调者,参与者

第一阶段

提交事务请求

  1. 询问
    协调者向所有参与者发送事务内容,询问是否提交,开始等待响应。
  2. 执行
    参与者执行事务操作,写undo 和 redo *1到事务日志,
  3. 参与者向协调者返回询问的响应
    如果参与者成功执行了事务,反馈给协调者Yes,表示可以执行;如果参与者执行失败,返回给协调者No响应,表示不可以执行。

第二阶段

执行事务提交

结果1:成功执行提交
  1. 发送提交请求
    协调者收到所有的Yes反馈,向所有参与者发送commit请求
  2. 事务提交
    参与者收到协调者的commit请求,开始正式提交事务,完成提交后释放占用的事务资源
  3. 反馈提交结果
    参与者完成正式提交之后,给协调者发送ACK响应
  4. 完成事务
    协调者接收到所有参与者的ACK反馈后,完成事务
结果2:执行事务中断

1.发送回滚请求
协调者收到参与者No反馈,向所有参与者发送rollback请求
2.事务回滚
参与者接收到rollback请求,按照undo日志执行回滚,完成后释放占用的事务资源。
3.反馈回滚结果
参与者完成回滚后,给协调者发送ACK消息
4.中断事务
协调者接收到所有参与者的ACK消息后,完成整体事务的中断

两阶段的问题:

  • 同步阻塞:一次事务请求中,参与者在等待其他参与者响应时无法做任何其他操作
  • 单点问题: 协调者处于单点位置,尤其在第二阶段(提交或者中断)会导致资源锁定。如发生故障,参与者占有的资源无法释放。
  • 数据不一致:在最终commit的过程中,如果发生网络故障或者其他原因导致只发送了部分commit,会造成只有部分执行了commit,产生数据的不一致,也有称作“脑裂”
  • 设计太过保守:如果协调者无法获取参与者的信息,则只能通过自身的超时机制来确认是否中断事务,容错机制不是特别完善,任何一个节点失败都会导致整个事务的失败,失败影响的范围较大。

三阶段提交

三阶段针对两阶段的缺点,做出改进,将2PC的第一阶段拆分,并且在协调者和参与者中都引入超时机制。

第一阶段

请求提交canCommit

  1. 事务询问
    协调者向所有参与者发送一个canCommit请求,询问是否可以执行事务提交操作。
  2. 各个参与者向协调者反馈询问的响应
    参与者在收到canCommit询问请求后,确认是否可以执行事务,可以回复Yes,并进入预备状态;否则回复No响应。

第二阶段

预备提交preCommit

结果1:在所有参与者回复Yes之后,执行事务预提交
  1. 协调者发送预提交请求
    协调者向所有参与者发送PreCommit请求,协调者进入Prepare状态。
  2. 事务预提交
    参与者收到preCommit之后,执行事务操作,写redo和undo信息到事务日志中。
  3. 反馈预提交结果
    参与者如果成功执行了事务操作,反馈给协调者ACK响应,并等待协调者最终执行,commit或者abort(注意此处的commit或者abort是对preCommit的处理,不是最终提交
结果2:中断preCommit,任何一个参与者向协调者发送No,或者协调者等待响应超时,则开始中断。
  1. 发送预中断请求
    协调者向所有参与者发送abort请求。
  2. 中断事务
    参与者收到协调者的abort请求,或者参与者等待请求超时,开始执行中断。

第三阶段

正式提交doCommit

结果1:执行正式提交
  1. 发送正式提交请求
    协调者正常工作,收到所有参与者的ACK响应,将从prepare转到commit状态,并向所有参与者发送doCommit请求。
  2. 事务正式提交
    参与者接收到doCommit请求后,正式提交事务,并释放锁定的事务资源。
  3. 反馈正式提交结果
    参与者如果成功执行了事务操作,反馈给协调者ACK响应,并等待协调者最终执行,commit或者abort(此处是正式提交阶段的commit或者abort)
  4. 完成事务
    协调者接收到所有参与者的ACK消息之后,完成事务。
结果2:中断事务 只要协调者收到任意一个参与者的No响应,则开始中断事务
  1. 发送中断请求
    协调者正常工作,向所有参与者发送abort请求。
  2. 事务回滚
    参与者收到abort请求之后,利用undo信息执行事务回滚操作,完成后释放锁定的事务资源。
  3. 反馈回滚结果
    参与者完成事务回滚之后,向协调者发送ACK消息
  4. 中断事务
    协调者接收到所有参与者的ACK消息后,完成中断事务

三阶段的优劣:

  • 减小了参与者阻塞的范围,在出现单点故障后仍然能达成一致。
  • 和2PC类似,如果参与者收到preCommit之后,发送网络异常,参与者仍旧会执行事务提交,导致数据的不一致。
  • 实现较为复杂
  • 网络通信量大,会增高延迟

2PC和3PC的图解

图片来自网络,可以作为简单分析了解。
两阶段:


两阶段提交图解

三阶段:


三阶段提交图解

相关介绍:
redo和undo日志:
redo日志用来重放,找到所有已经commit的事务,根据redo log重做,记>录在MySQL存储页的物理修改;undo用来回滚,找到所有uncommitted的事务,利用undo来回滚,记录逻辑的修改(insert->delete)。另外undo也有自己的redo日志。对应的过程参考下图,过程A先于过程B:

undo和redo写入过程

参考:
《从Paxos到Zookeeper》
《MySQL innodb存储引擎》
分布式两阶段,三阶段的理解:http://www.cnblogs.com/binyue/p/3678390.html
分布式一致性到共识机制PAXOS:http://www.cnblogs.com/binyue/p/8645565.html
分布式事务,两阶段,三阶段:http://www.hollischuang.com/archives/681

演示的PPT整理:PPT

推荐阅读更多精彩内容