2pc,3pc就是解决分布式事务(参与事务的事务管理器,参与者位于不同的节点)的原子性,一致性问题,而且这些算法并不是只能单一的应用于某个问题上,有很多问题都可以转化为用这些算法解决。
分布式事务
通常把一个数据库内部的事务处理,如对多个表的操作,作为本地事务看待。数据库的事务处理对象是本地事务,而分布式事务处理的对象是全局事务。 所谓全局事务,是指分布式事务处理环境中,多个数据库可能需要共同完成一个工作,这个工作即是一个全局事务,例如,一个事务中可能更新几个不同的数据库(可以是不同的应用对应的数据库,也可以是副本??)。对数据库的操作发生在系统的各处但必须全部被提交或回滚。此时一个数据库对自己内部所做操作的提交不仅依赖本身操作是否成功,还要依赖与全局事务相关的其它数据库的操作是否成功,如果任一数据库的任一操作失败,则参与此事务的所有数据库所做的所有操作都必须回滚。 一般情况下,某一数据库无法知道其它数据库在做什么。因此,在一个 DTP 环境中,交易中间件是必需的,由它通知和协调相关数据库的提交或回滚。而一个数据库只将其自己所做的操作(可恢复)影射到全局事务中。
2PC
在事务处理, 关系型数据库, 以及计算机网络中, 2阶段提交协议(2pc)是一种典型的原子提交协议. 他是一种由协调器来处理分布式原子参与者 是提交或者 回滚事务的分布式算法
二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。2PC就是用来解决分布式事务的原子性问题。所谓的两个阶段是指:第一阶段:准备阶段(投票阶段)和第二阶段:提交阶段(执行阶段)
2 个阶段:
- 准备阶段
务协调者(事务管理器)给每个参与者(资源管理器)发送Prepare消息,每个参与者要么直接返回失败(如权限验证失败),要么在本地执行事务,写本地的redo和undo日志,但不提交,然后向协调者反馈YES,NO。
- 提交阶段
如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(Rollback)消息;否则,发送提交(Commit)消息;参与者根据协调者的指令执行提交或者回滚操作,释放所有事务处理过程中使用的锁资源。(注意:必须在最后阶段释放锁资源)。
优点
2PC的优点是很显然的,原理简单,实现方便。目前,绝大多数关系型数据库都是采用两阶段提交协议来完成分布式事务处理的。(也就是上边的2pc过程应用于关系型数据库的分布式事务)
不足:
由于二阶段提交存在着诸如同步阻塞、单点问题、脑裂等缺陷,所以,研究者们在二阶段提交的基础上做了改进,提出了三阶段提交。
同步阻塞: 执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态,各个参与者在等待协调者发出提交或中断请求时,会一直阻塞,而协调者的发出时间要依赖于所有参与者的响应时间,如果协调者宕机了(单点, 注意这边是协调者宕机),那么他就一直阻塞在这,而且无法达成一致(3PC引入了超时提交解决)。
单点故障: 由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
数据不一致
出现分区,或者网络故障。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。
太过保守: 2pc没有设计相应的容错机制,当任意一个参与者节点宕机,那么协调者超时没收到响应,就会导致整个事务回滚失败。
二阶段无法解决的问题: 协调者(在第二阶段)发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
使用原则:
- 能不用, 就不用
- 加上超时机制
3PC
3PC分为3次交互,3PC,即三阶段提交,是2阶段提交的改进版,其将二阶段提交协议的“准备阶段”一份为二,形成了cancommit,precommit,do commit三个阶段。
- 第一阶段,CanCommit阶段
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应 正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No (这边并不会执行那些操作)
- 第二阶段 PreCommit阶段
协调者根据参与者的反应情况来决定是否可以继续事务的preCommit操作
=========================================================
加入所有的yes响应, 那么会执行事务的预执行
1.发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
2.事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。(不会commit)
3.响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
===========================================================
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
1.发送中断请求 协调者向所有参与者发送abort请求。
2.中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
进入第二阶段: 第二阶段是预提交, 都确认预提交成功后, 进入第三阶段
- 第三阶段 doCommit阶段
这个阶段就是真正的事务提交了, 不过也会根据之前的响应,来做
执行提交 或者中断事务, 不过执行任何一个操作, 都需要向协调者返回应答信号, 然后协调者完成事务或者中断事务
3pc 是在2pc的基础上增加了一次交互, 也就是预提交. 只要预提交成功, 则一定要保证docommot提交成功, 即使下一阶段不可用, 或者调用超时, 这是基本思想. 在工业环境中, 一般是通过重试补偿的策略来保证doCommit的提交成功
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,会继续进行事务的提交。
与两阶段提交不同的是,三阶段提交有两个改动点。
1、引入超时机制。(超时提交策略,当第三阶段参与者等待协调者超时后会提交事务,解决参与者同步阻塞问题,同时能在发生单点故障时,继续达成一致)
2、在第一阶段和第二阶段中插入一个准备阶段。(也是为了减少同步阻塞的发生范围)
3pc解决的问题 主要是通过超时
1 协调者出现故障(单点) 2 协调者与参与者之间出现网络故障
二阶段无法解决的问题:协调者(在第二阶段)发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit(所以产生新的协调者之后,可以确定事务的状态,这就解决了单点)。而不会一直持有事务资源并处于阻塞状态。
不足:
3PC无法解决:数据不一致以及太过保守问题。
但是这种机制也会导致数据一致性问题,因为,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。