什么是2PC
二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。
二阶段是指:
第一阶段- 请求阶段(表决阶段)
第二阶段 - 提交/回滚阶段(执行阶段)
请求阶段
事务协调者通知每个参与者准备提交或取消事务,然后进入表决过程,参与者要么在本地执行事务,写本地的redo和undo日志,但不提交,到达一种"万事俱备,只欠东风"的状态。
请求阶段,参与者将告知协调者自己的决策:同意(事务参与者本地作业执行成功)或取消(本地作业执行故障)
提交阶段
在该阶段,写调整将基于第一个阶段的投票结果进行决策:提交或取消。
当且仅当所有的参与者同意提交事务,协调者才通知所有的参与者提交事务,否则协调者将通知所有的参与者取消事务。
两阶段提交的缺点
1️⃣ 同步阻塞问题
执行过程中,所有参与节点都是事务阻塞型的。
当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
2️⃣ 单点故障
由于协调者的重要性,一旦协调者发生故障,参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。
(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
3️⃣ 数据不一致
在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。
而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象
什么是3PC
三阶段提交协议在协调者和参与者中都引入超时机制,并且把两阶段提交协议的第一个阶段分成了两步:询问,然后再锁资源,最后真正提交。
请求阶段
3PC的canCommit阶段其实和2PC的准备阶段很像,协调者向参与者发送canCommit请求,参与者如果可以提交就返回yes响应,否则返回no响应,这一阶段主要做SQL校验。
预提交阶段
协调者根据参与者canCommit阶段的响应来决定是否可以继续事务的preCommit操作,根据响应情况,有下面两种可能:
1️⃣ 反馈成功
协调者从所有参与者得到的反馈都是yes。
那么进行事务的预执行,协调者向所有参与者发送preCommit请求,并进入prepared阶段。参与泽和接收到preCommit请求后会执行事务操作,并将undo和redo信息记录到事务日志中,如果一个参与者成功地执行了事务操作,则返回ACK响应,同时开始等待最终指令。
2️⃣ 反馈失败
协调者从所有参与者得到的反馈有一个是No或是等待超时之后协调者都没收到响应。
那么就要中断事务,协调者向所有的参与者发送abort请求。参与者在收到来自协调者的abort请求,或超时后仍未收到协调者请求,执行事务中断。
提交阶段
协调者根据参与者preCommit阶段的响应来决定是否可以继续事务的doCommit操作,根据响应情况,有下面两种可能:
1️⃣ 反馈成功
阶段2所有参与者均反馈ack响应,执行真正的事务提交。
协调者接收到参与者发送的ACK响应,那么它将从预提交状态进入到提交状态,并向所有参与者发送doCommit请求,参与者接收到doCommit请求后,执行正式的事务提交,并在完成事务提交之后释放所有事务资源,并向协调者发送haveCommitted的ACK响应。那么协调者收到这个ACK响应之后,完成任务。
2️⃣ 反馈失败
阶段2任何一个参与者反馈no,或者等待超时后协调者尚无法收到所有参与者的反馈,即中断事务。
注意:进入阶段3后,无论协调者出现问题,或者协调者与参与者网络出现问题,都会导致参与者无法接收到协调者发出的doCommit请求或abort请求。此时,参与者都会在等待超时之后,继续执行事务提交。
2PC和3PC的区别
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。
但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。