分析&回答
2PC(两阶段提交)
- 所谓的两个阶段是指:第一阶段:准备阶段(投票阶段) 和第二阶段:提交阶段(执行阶段)。
- 2PC是一个非常经典的强一致、中心化的原子提交协议。
举例来说明两阶段提交协议的工作过程:
A组织B、C和D三个人去爬山:如果所有人都同意去爬山,那么活动将举行;如果有一人不同意去爬山,那么活动将取消。首先A将成为该活动的协调者,B、C和D将成为该活动的参与者。用2PC算法解决该问题的过程如下:
- 阶段1:
- A发邮件给B、C和D,提出下周三去爬山,问是否同意。那么此时A需要等待B、C和D的邮件。
- B、C和D分别查看自己的日程安排表。B、C发现自己在当日没有活动安排,则发邮件告诉A它们同意下周三去爬山。由于某种原因, D白天没有查看邮 件。那么此时A、B和C均需要等待。到晚上的时候,D发现了A的邮件,然后查看日程安排,发现周三当天已经有别的安排,那么D回复A说活动取消吧。
- 阶段2:
- 此时A收到了所有活动参与者的邮件,并且A发现D下周三不能去爬山。那么A将发邮件通知B、C和D,下周三爬山活动取消。
- 此时B、C回复A“太可惜了”,D回复A“不好意思”。至此该事务终止。
2PC存在问题
1)性能问题
无论是在第一阶段的过程中,还是在第二阶段,所有的参与者资源和协调者资源都是被锁住的,只有当所有节点准备完毕,事务 协调者 才会通知进行全局提交,
参与者 进行本地事务提交后才会释放资源。这样的过程会比较漫长,对性能影响比较大。
2)单节点故障
由于协调者的重要性,一旦 协调者 发生故障。参与者 会一直阻塞下去。尤其在第二阶段,协调者 发生故障,那么所有的 参与者 还都处于
锁定事务资源的状态中,而无法继续完成事务操作。(虽然协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
2PC出现单点问题的三种情况:
协调者正常,参与者宕机
- 由于 协调者 无法收集到所有 参与者 的反馈,会陷入阻塞情况。
- 解决方案:引入超时机制,如果协调者在超过指定的时间还没有收到参与者的反馈,事务就失败,向所有节点发送终止事务请求。
协调者宕机,参与者正常
- 无论处于哪个阶段,由于协调者宕机,无法发送提交请求,所有处于执行了操作但是未提交状态的参与者都会陷入阻塞情况.
- 解决方案:引入协调者备份,同时协调者需记录操作日志.当检测到协调者宕机一段时间后,协调者备份取代协调者,并读取操作日志,向所有参与者询问状态。
协调者和参与者都宕机
- 1、发生在第一阶段: 因为第一阶段,所有参与者都没有真正执行commit,所以只需重新在剩余的参与者中重新选出一个协调者,新的协调者在重新执行第一阶段和第二阶段就可以了。
- 2、发生在第二阶段 并且 挂了的参与者在挂掉之前没有收到协调者的指令。也就是上面的第4步挂了,这是可能协调者还没有发送第4步就挂了。这种情形下,新的协调者重新执行第一阶段和第二阶段操作。
- 3、发生在第二阶段 并且 有部分参与者已经执行完commit操作。就好比这里订单服务A和支付服务B都收到协调者 发送的commit信息,开始真正执行本地事务commit,但突发情况,Acommit成功,B确挂了。这个时候目前来讲数据是不一致的。虽然这个时候可以再通过手段让他和协调者通信,再想办法把数据搞成一致的,但是,这段时间内他的数据状态已经是不一致的了! 2PC 无法解决这个问题。
3PC(三阶段提交)
3PC是2PC的改进版本,主要是为了解决两阶段提交协议的阻塞问题,2PC存在的问题是当协作者崩溃时,参与者不能做出最后的选择。因此参与者可能在协作者恢复之前保持阻塞。
- 引入超时机制。同时在协调者和参与者中都引入超时机制。
- 在第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前各参与节点的状态是一致的。
CanCommit阶段
之前2PC的一阶段是本地事务执行结束后,最后不Commit,等其它服务都执行结束并返回Yes,由协调者发生commit才真正执行commit。而这里的CanCommit指的是 尝试获取数据库锁 如果可以,就返回Yes。
这阶段主要分为2步:
事务询问
协调者 向 参与者 发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待 参与者 的响应。响应反馈
参与者 接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
PreCommit阶段
在阶段一中,如果所有的参与者都返回Yes的话,那么就会进入PreCommit阶段进行事务预提交。这里的PreCommit阶段 跟上面的第一阶段是差不多的,只不过这里 协调者和参与者都引入了超时机制 (2PC中只有协调者可以超时,参与者没有超时机制)。
3、DoCommit阶段
这里跟2PC的阶段二是差不多的,参考2PC。
3PC存在问题
如果进入PreCommit后,Coordinator发出的是abort请求,假设只有一个Cohort收到并进行了abort操作,而其他对于系统状态未知的Cohort会根据3PC选择继续Commit,此时系统状态发生不一致性。
2PC和3PC的不同
对于协调者(Coordinator)和参与者(Cohort)都设置了超时机制(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到cohort的消息则默认失败)。
在2PC的准备阶段和提交阶段之间,插入预提交阶段,使3PC拥有CanCommit、PreCommit、DoCommit三个阶段。
PreCommit是一个缓冲,保证了在最后提交阶段之前各参与节点的状态是一致的。
反思&扩展
三阶段提交也存在一些缺陷,要彻底从协议层面避免数据不一致,可以采用Paxos 或者 Raft 算法。
** 一般Paxos、 Raft不作为面试评估项!可以不用继续了哈
**
Paxos算法
分布式系统中的节点通信存在两种模型:[共享内存](Shared memory)和 [消息传递](Messages passing)。
基于消息传递通信模型的分布式系统,不可避免的会发生以下错误:进程可能会慢、被杀死或者重启,消息可能会延迟、丢失、重复,在基础Paxos场景中,先不考虑可能出现消息篡改即"拜占庭将军问题"的情况。
Paxos算法解决的问题是在一个可能发生上述异常的分布式系统中如何就某个值达成一致,保证不论发生以上任何异常,都不会破坏决议的一致性。主要有三类节点:
- 提议者(Proposer):提议一个值;
- 接受者(Acceptor):对每个提议进行投票;
- 告知者(Learner):被告知投票的结果,不参与投票过程。
Raft算法
Raft 是一种基于日志复制的一致性算法,算法也是一种少数服从多数的算法,在任何时候一个服务器可以扮演以下角色之一:
- Leader:负责 Client 交互 和 log 复制,同一时刻系统中最多存在一个
- Follower:被动响应请求 RPC,从不主动发起请求 RPC
- Candidate : 由Follower 向Leader转换的中间状态
Paxos算法与 Raft算法的差异
- Raft强调是唯一leader的协议,此leader至高无上
- Raft:新选举出来的leader拥有全部提交的日志,而 Paxos 需要额外的流程从其他节点获取已经被提交的日志,它允许日志有空洞
- 相同点:得到大多数的赞成,这个 entries 就会定下来,最终所有节点都会赞成
喵呜面试助手: 一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!