一.二阶段提交(2PC)
两阶段提交又称2PC,2PC是一个非常经典的强一致、中心化的原子提交协议。
中心化是指协议中有两类节点:
一个是中心化协调者节点(coordinator)
N个参与者节点(partcipant)
两个阶段:
第一阶段:投票(准备)阶段
第二阶段:提交/执行阶段
第一阶段:准备阶段
第一阶段主要分为3步
1)事务询问
协调者 向所有的 参与者 发送事务预处理请求,称之为Prepare,并开始等待各 参与者 的响应(会发生阻塞)。
PS:预处理请求:上级告诉你待会要开个会,你准备下环境。
2)执行本地事务
各个 参与者 节点执行**本地事务**操作,但在执行完成后并**不会真正提交数据库本地事务**,而是先向 协调者 报告说:“我这边可以处理了/我这边不能处理”
3)各参与者向协调者反馈执行结果响应
如果 参与者 成功执行了**本地事务**操作,那么就反馈给协调者 Yes 响应,表示事务可以执行,
如果没有 参与者 成功执行**本地事务**,那么就反馈给协调者 No 响应,表示事务不可以执行。
第一阶段执行完后,会有两种可能。1、所有都返回Yes. 2、有一个或者多个返回No,leader阻塞。
第二阶段:提交/执行阶段(成功流程)
成功条件:**所有参与者都返回Yes。**
第二阶段主要分为两步
1)所有的参与者反馈给协调者的信息都是Yes,那么就会执行事务提交
协调者 向 所有参与者 节点发出Commit请求.
2)事务提交
参与者 收到Commit请求之后,就会正式执行本地事务Commit操作,并向协调者发送一个"已提交"(committed)的响应。并在完成提交之后释放整个事务执行期间占用的事务资源,leader也会commit自己的事务。
如果协调者收到所有参与者的“已提交”响应,则它将向所有参与者发送一个“完成”(done)的响应。
第二阶段:提交/执行阶段(异常流程)
异常条件:**任何一个 参与者 向 协调者 反馈了 No 响应,或者等待超时(网络抖动)之后,协调者尚未收到所有参与者的反馈响应。**
异常流程第二阶段也分为两步
1)发送回滚请求
协调者 向所有参与者节点发出 RoollBack 请求.
2)事务回滚
参与者 接收到RoollBack请求后,会回滚本地事务。
2PC优缺点
优点:
2PC协议的主要优点是能够确保所有参与者在提交阶段的状态一致,从而保证分布式系统的数据一致性。
缺点:
通过上面的演示,很容易想到2pc所带来的缺陷
1)性能问题
无论是在第一阶段的过程中,还是在第二阶段,**所有的参与者资源和协调者资源都是被锁住的**,只有当所有节点准备完毕,事务 **协调者** 才会通知进行全局提交。
**参与者** 进行本地事务提交后才会释放资源。这样的**过程会比较漫长,对性能影响比较大。**
2)单节点故障
由于协调者的重要性,一旦 协调者 发生故障。参与者 会一直阻塞下去。尤其在第二阶段,协调者 发生故障,那么所有的 参与者 还都处于锁定事务资源的状态中,而无法继续完成事务操作。(虽然协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
2PC出现单点问题的三种情况
(1)协调者正常,参与者宕机
由于 协调者 无法收集到所有 参与者 的反馈,会陷入阻塞情况。
解决方案:引入超时机制,如果协调者在超过指定的时间还没有收到参与者的反馈,事务就失败,向所有节点发送终止事务请求。
(2)协调者宕机,参与者正常
无论处于哪个阶段,由于协调者宕机,无法发送提交请求,所有处于执行了操作但是未提交状态的参与者都会陷入阻塞情况.
解决方案:引入协调者备份,同时协调者需记录操作日志.当检测到协调者宕机一段时间后,协调者备份取代协调者,并读取操作日志,向所有参与者询问状态。
(3)协调者和参与者都宕机
1)发生在第一阶段: 因为第一阶段,所有参与者都没有真正执行commit,所以只需重新在剩余的参与者中重新选出一个协调者,新的协调者在重新执行第一阶段和第二阶段就可以了。
2)发生在第二阶段 并且 挂了的参与者在挂掉之前没有收到协调者的指令。也就是上面的第4步挂了,这是可能协调者还没有发送第4步就挂了。这种情形下,新的协调者重新执行第一阶段和第二阶段操作。
3)发生在第二阶段 并且 有部分参与者已经执行完commit操作。就好比这里订单服务A和支付服务B都收到协调者 发送的commit信息,开始真正执行本地事务commit,但突发情况,Acommit成功,B确挂了。这个时候目前来讲数据是不一致的。虽然这个时候可以再通过手段让他和协调者通信,再想办法把数据搞成一致的,但是,这段时间内他的数据状态已经是不一致的了! 2PC 无法解决这个问题。
4)脑裂(数据不一致)
当协调者向所有参与者commit请求后,发生局部网络异常或者协调者尚未发送完commit请求之前自身发送崩溃。导致只有部分参与者收到commit请求。这部分收到请求的参与者就会进行事务提交,而没收到commit请求的参与者无法事务提交。因此造成了整个分布式系统数据不一致。
5)网络分区问题
网络分区是指在分布式系统中,网络被划分成两个或多个不连通的子网,导致节点之间无法进行通信。这种情况下,如果存在一个或多个节点无法与其他节点进行通信,则可能会导致整个分布式系统的故障或数据不一致。
解决方法:2PC协议通常采用超时机制和日志记录来处理网络分区。超时机制可以确保当节点无法在规定时间内响应请求时,协调者节点将进行适当的处理。日志记录可以确保在出现网络分区或节点故障时,可以通过重放日志来恢复事务状态。
Zookeeper 2PC会导致的问题:
leader发送预提交之后等待follower回复ack,如果follower回复的ack过半那么leader就会进行后续
1.leader 预提交 follower发送ack 超过一半会提交,如果没有超过一半会导致什么?(回滚,提案收回)
2.leader预提交的时候挂了会有哪些操作?
重新选举leader,即使宕机的原leader以follower的角色启动,但是日志还是会丢弃,因为新选举出来的leader没有该日志,无法进行同步
3.follower网络抖动没有收到commit会怎么办?(阻塞)
4.有些follower之前就没有接收到proposal预提交(回滚)
5.如果接受到commit的机器有部分或者是全部都commit失败呢?(回滚)
6.leader发送commit请求后就down了,会发生什么动作?
日志不会丢弃,会继续同步到其他节点中去。