分布式理论系列(二)2PC 到 3PC 到 Paxos 到 Raft 到 Zab
本文介绍一致性实现的几种方案: 2PC 到 3PC 到 Paxos 到 Raft 到 Zab
两类一致性(操作原子性与副本一致性)
2PC 3PC
协议用于保证属于多个数据分片上的操作的原子性。这些数据分片可能分布在不同的服务器上,2PC 协议保证多台服务器上的操作要么全部成功,要么全部失败。Paxos Raft Zab
协议用于保证同一个数据分片的多个副本之间的数据一致性。当这些副本分布到不同的数据中心时,这个需求尤其强烈。
一、2PC(阻塞、数据不一致问题、单点问题)
Two-Phase Commit(两阶段提交) 是计算机网络尤其是在数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务处理过程中能够保持原子性和致性而设计的一种算法。通常,二阶段提交协议也被认为是一种一致性协议,用来保证分布式系统数据的一致性。绝大部分的关系型数据库都是采用二阶段提交协议来完成分布式事务处理。
1.1 协议介绍
阶段一:提交事务请求(投票阶段)
- 事务询问
协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应。
- 执行事务
各参与者节点执行事务操作,并将 Undo 和 Redo 信息计入事务日志中。
- 各参与者向协调者反馈事务询问的响应
如果参与者成功执行了事务操作,那么就反馈给协调者 Yes 响应,表示事务可以执行;如果参与者没有成功执行事务,那么就反馈给协调者 No 响应,表示事务不可以执行。
阶段二:执行事务提交(执行阶段)
(1)执行事务提交
如果所有参与者的反馈都是 Yes 响应,那么
- 发送提交请求
协调者向所有参与者节点发出Commit请求
- 事务提交
参与者接收到Commit请求后,会正式执行事务提交操作,并在完成提交之后释放在整个事务执行期间占用的事务资源
- 反馈事务提交结果
参与者在完成事务提交之后,向协调者发送ACK信息
- 完成事务
协调者接收到所有参与者反馈的ACK消息后,完成事务
(2)中断事务
任何一个参与者反馈了 No 响应,或者在等待超时之后,协调者尚无法接收到所有参与者的反馈响应,那么就会中断事务。
- 发送回滚请求
协调者向所有参与者节点发出Rollback请求
- 事务回滚
参与者接收到rollback请求后,会利用其在阶段一中记录的Undo信息来执行事务回滚操作,并在完成回滚之后释放整个事务执行期间占用的资源
- 反馈事务回滚结果
参与者在完成事务回滚之后,向协调者发送ACK信息
- 中断事务
协调者接收到所有参与者反馈的ACK信息后,完成事务中断
1.2 优缺点
优点:原理简单、实现方便
缺点:同步阻塞、单点问题、数据不一致、太过保守
(1)同步阻塞
同步阻塞会极大地限制分布式系统的性能。在二阶段提交的执行过程中,所有参与该事务操作的逻辑都处于阻塞状态,各个参与者在等待其他参与者响应的过程中,将无法进行其他任何操作。
(2)单点问题
一旦协调者出现问题,那么整个二阶段提交流程将无法运转,更为严重的是,如果是在阶段二中出现问题,那么其他参与者将会一直处于锁定事务资源的状态中,无法继续完成事务操作。
(3)数据不一致
在阶段二,当协调者向所有参与者发送commit请求之后,发生了局部网络异常或协调者在尚未发完commit请求之前自身发生了崩溃,导致最终只有部分参与者接收到了commit请求,于是这部分参与者执行事务提交,而没收到commit请求的参与者则无法进行事务提交,于是整个分布式系统出现了数据不一致性现象。
(4)太过保守
如果参与者在与协调者通信期间出现故障,协调者只能靠超时机制来判断是否需要中断事务,这个策略比较保守,需要更为完善的容错机制,任意一个节点的失败都会导致整个事务的失败。
二、3PC(解决2PC的阻塞,但还是可能造成数据不一致)
Three-Phase Commit,三阶段提交,分为 CanCommit、PreCommit、doCommit 三个阶段。
2.1 协议介绍
为了避免在通知所有参与者提交事务时,其中一个参与者 crash 不一致时,就出现了三阶段提交的方式。三阶段提交在两阶段提交的基础上增加了一个 preCommit 的过程,当所有参与者收到 preCommit 后,并不执行动作,直到收到 commit 或超过一定时间后才完成操作。
1、阶段一CanCommit
(1)事务询问
协调者向各参与者发送CanCommit的请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应
(2)参与者向协调者反馈询问的响应
参与者收到CanCommit请求后,正常情况下,如果自身认为可以顺利执行事务,那么会反馈Yes响应,并进入预备状态,否则反馈No。
2、阶段二PreCommit
(1)执行事务预提交
如果协调者接收到各参与者反馈都是 Yes,那么执行事务预提交
- 发送预提交请求
协调者向各参与者发送 preCommit 请求,并进入 prepared 阶段
- 事务预提交
参与者接收到 preCommit 请求后,会执行事务操作,并将Undo和Redo信息记录到事务日记中
- 各参与者向协调者反馈事务执行的响应
如果各参与者都成功执行了事务操作,那么反馈给协调者 Ack 响应,同时等待最终指令,提交 commit 或者终止 abort
(2)中断事务
如果任何一个参与者向协调者反馈了No响应,或者在等待超时后,协调者无法接收到所有参与者的反馈,那么就会中断事务。
- 发送中断请求
协调者向所有参与者发送 abort 请求
- 中断事务
无论是收到来自协调者的 abort 请求,还是等待超时,参与者都中断事务
3、阶段三doCommit
(1)执行提交
- 发送提交请求
假设协调者正常工作,接收到了所有参与者的ack响应,那么它将从预提交阶段进入提交状态,并向所有参与者发送doCommit请求
- 事务提交
参与者收到doCommit请求后,正式提交事务,并在完成事务提交后释放占用的资源
- 反馈事务提交结果
参与者完成事务提交后,向协调者发送ACK信息
- 完成事务
协调者接收到所有参与者ack信息,完成事务
(2)中断事务
假设协调者正常工作,并且有任一参与者反馈No,或者在等待超时后无法接收所有参与者的反馈,都会中断事务
- 发送中断请求
协调者向所有参与者节点发送abort请求
- 事务回滚
参与者接收到 abort 请求后,利用 undo 日志执行事务回滚,并在完成事务回滚后释放占用的资源
- 反馈事务回滚结果
参与者在完成事务回滚之后,向协调者发送 ack 信息
- 中断事务
协调者接收到所有参与者反馈的 ack 信息后,中断事务。
阶段三可能出现的问题:
协调者出现问题、协调者与参与者之间网络出现故障。不论出现哪种情况,最终都会导致参与者无法及时接收到来自协调者的 doCommit 或是 abort 请求,针对这种情况,参与者都会在等待超时后,继续进行事务提交(timeout 后中断事务)。
2.2 优缺点
优点:降低参与者阻塞范围,并能够在出现单点故障后继续达成一致
缺点:引入 preCommit 阶段,在这个阶段如果出现网络分区,协调者无法与参与者正常通信,参与者依然会进行事务提交,造成数据不一致。
三、Paxos(解决单点问题)
Paxos 算法的目标就是要保证提交多个提案时最终有一个提案会被选定,当提案被选定后,进程最终也能获取到被选定的提案。
四、Raft(解决 Paxos 的实现难度)
动画演示 Raft:http://thesecretlivesofdata.com/raft/
五、ZAB
基本与 raft 相同。在一些名词的叫法上有些区别,如 ZAB 将某一个 leader 的周期称为 epoch,而 raft 则称之为 term。实现上也有些许不同,如 raft 保证日志连续性,心跳方向为 leader 至 follower,ZAB 则相反。
参考:
- 《分布式理论系列》:https://segmentfault.com/a/1190000004474543
- 从 Paxos 到 Zookeeper : 分布式一致性原理与实践
- 《一致性算法(Paxos、Raft、ZAB)视频》:https://www.bilibili.com/video/av21667358/
- 《分布式事务中2PC与3PC的区别》:https://blog.csdn.net/yyd19921214/article/details/68953629
每天用心记录一点点。内容也许不重要,但习惯很重要!
原文地址:https://www.cnblogs.com/binarylei/p/9906044.html