分布式环境下,存在着多个节点,需要保证不同节点之间的数据一致性,提出了分布式事务,而2PC和3PC则是分布式事务的表现形式。
一、什么是2PC
2PC即两阶段提交,顾名思义就是将事务的提交过程分成了两个阶段,P是准备阶段(Prepare),C是提交阶段(Commit)。
准备阶段,事务管理器给每个参与者发送Prepare消息,每个参与者在本地执行事务,并写本地的Undo/Redo日志,此时事务没有提交。
提交阶段,如果事务管理器收到了参与者的执行失败或者超时消息时,直接给每个参与者发送Rollback消息,否则,发送Commit消息。
参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。就关系型数据库Mysql、Oracle的处理流程一样,事实上他们也是支持两阶段提交协议,下面详细理一理2PC的执行流程。
二、2PC执行流程
2.1 执行流程
在这里插入图片描述第一阶段:
① 事务询问,事务管理器向所有参与者发送事务内容,询问事务是否执行,并开始等待
② 参与者接收到请求,开始执行事务(写入本地Undo/Redo日志)
③ 各参与者向协调者反馈事务的执行情况
第二阶段:
① 发送提交请求,事务管理器向所有参与者发出Commit/Rollback请求
② 事务提交,参与者收到Commit/Rollback请求后,如果是Commit会正式执行事务提交操作,如果是Rollback会根据之前记录的Undo日志进行回滚,并在完成提交之后释放整个事务执行期间占用的事务资源
③ 反馈事务提交结果,参与者在完成事务提交之后,向协调者发送ack信息,协调者接收到所有参与者反馈的ack信息后,完成事务
第一阶段主要是为了让各个参与者投票是否让事务进行,第二阶段主要做了两件事情,执行事务,还有就是对事务的执行结果进行投票。
2.2 特点
2PC的优点也很明显:原理简单,实现方便,但也存在一些问题:
同步阻塞:
二阶段提交协议存在最明显的问题也是最大的一个问题就是同步阻塞,在整个提交过程中,所有参与者操作的逻辑都处于阻塞状态,每个参与者在等待管理器的响应时,无法进行其他操作,极大的限制了分布式的性能。
单点问题:
协调者在整个提交的过程中都很重要,如果协调者出了问题,那么整个过程都失败,更严重的是参与者会一直处于资源锁定的状态,从而无法完成事务操作。
数据不一致:
假设当协调者向所有参与者发送commit之后,发生网络抖动协调者在未发送完所有Commit之前自身挂掉了,导致只有部分参与者收到commit请求,或者是Prepare阶段成功,Commit阶段失败,这都会导致数据不一致。
过于保守:
如果在二阶段提交的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的响应信息,这时候协调者只有依赖自身的超时机制来对事务进行回滚。或者说二阶段提交没有设计比较完善的容错机制。
三、什么是3PC
3PC是2PC的改进版,将事务的第一阶段一份为二,分多了一个阶段。组成了CanCommit、PreCommit和doCommit三个阶段。
在这里插入图片描述
第一阶段:
① 事务询问,协调者向所有的参与者发送一个包含事务内容的请求,询问是否可以执行事务提交操作,并开始等待各参与者的响应。
② 参与者在接收到来自协调者的包含了事务内容的请求后,正常情况下,如果自身认为可以顺利执行事务,则反馈Yes响应,并进入预备状态,否则反馈No响应。
第二阶段:
协调者在得到所有参与者的响应之后,会根据结果有2种执行操作的情况:执行事务预提交,或者中断事务。假如所有参与反馈的都是Yes,那么就会执行事务预提交。若任一参与者反馈了No响应,或者在等待超时后,协调者尚无法接收到所有参与者反馈,则中断事务。
如果是执行事务请求,需要做三步:
① 发送预提交请求:协调者向所有参与者节点发出preCommit请求,并进入prepared阶段。
② 事务预提交:参与者接收到preCommit请求后,会执行事务操作,并将Undo和Redo信息记录到事务日志中。
③ 各参与者向协调者反馈事务执行的结果:若参与者成功执行了事务操作,那么反馈Ack
如果是回滚请求,需要做两步:
① 发送中断请求:协调者向所有参与者发出abort请求。
② 中断事务:无论是收到来自协调者的abort请求或者等待协调者请求过程中超时,参与者都会中断事务
第三阶段:
该阶段做真正的事务提交或者完成事务回滚,参与者会根据接收到协调者的请求,进而判断是需要事务的提交还是回滚。如果出现网络抖动或其他问题,最终导致参与者无法收到协调者发来的请求,针对这种情况,参与者会在等待超时之后,默认认为其他参与者接收时成功的,所以会进行事务的提交。
四、2PC与3PC的比较
到这里,你可能还不是很明白2PC和3PC的区别,不能理解3PC为什么要加多一个阶段。
首先3PC对于协调者和参与者都设置了超时机制,避免了参与者在长时间无法与协调者节点通讯的情况下,无法释放资源的问题。(在2PC中,只有协调者拥有超时机制,即如果在一定时间内没有收到参与者的消息则默认失败)3PC设计了参与者自身拥有超时机制会在超时后,自动进行本地commit从而进行释放资源。而这种机制也侧面降低了整个事务的阻塞时间和范围。
通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较于2PC而言,多设置了一个缓冲阶段保证了在最后提交阶段之前各参与节点的状态是一致的 。就像我们平常在提交代码之前会Review一下,以确保正常。
但是3PC并没有完全解决数据不一致的问题。
五、最后再唠唠嗑
事实上,我并不觉得3PC就比一定比2PC好,3PC解决的是同步阻塞和单点问题导致参与者一直被阻塞的问题,数据一致性并没有完成解决。如果系统对数据一致性和实时性没有很高的要求,对于普通数千并发的系统来说,我感觉2PC就足够了,毕竟实现起来更简单,而且参与者被阻塞的概率其实是比较小的。所以还是要根据实际情况实际分析。
网友评论