X/Open DTP
X/Open DTP(X/Open Distributed Transaction Processing Reference Model) 是X/Open 这个组织定义的一套分布式事务的标准。
DTP基础组件( AM3):
- Application Program(AP) — 应用程序
- Transaction Manager(TM) — 事务管理器
- Resource Manager(RM) — 资源管理器
- Communication Resource Managers(CRMs)— 通讯资源管理器
在这个模型中,通常事务管理器(TM)是交易中间件,资源管理器(RM)是数据库,通信资源管理器(CRM)是消息中间件。XA则是DTP模型定义TM和RM之前通讯的接口规范,XA接口函数由数据库厂商提供。TM交易中间件用它来通知数据库事务的开始、结束以及回滚。2PC和3PC就是根据这种思想衍生而来。
2PC
2PC,二阶段提交协议,即将事务的提交过程分为两个阶段来进行处理:准备阶段和提交阶段。事务的发起者称为协调者,事务的执行者称为参与者。
执行阶段
- 准备提交阶段(Prepare)
- 提交阶段(Commit/Rollback)
参与角色
- 协调者(coordinator)
- 参与者(participants)
执行流程
阶段1:准备阶段
- 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待所有参与者答复
- 各参与者执行事务操作,将Undo和 Redo信息记入事务日志中(不提交事务)
- 如参与者执行成功,给协调者反馈 YES,即可以提交;如执行失败,给协调者反馈NO,即不可以提交
阶段2:提交阶段
此阶段分两种情况:
- 所有参与者反馈YES
- 任意一个参与者反馈NO
提交事务[Commit](所有参与者反馈YES):
-
协调者向所有参与者发出正式提交事务的请求
-
各参与者执行提交,并释放整个事务期间占用的资源
-
各参与者向协调者反馈Ack完成的消息
-
协调者收到所有参与者反馈的Ack消息后,即完成事务提交
示意图如下:
中断事务[Rollback](任意一个参与者反馈NO):
-
协调者向所有参与者发出回滚请求
-
参与者使用阶段1中的Undo信息执行回滚操作,并释放整个事务期间占用的资源
-
各参与者向协调者反馈Ack完成的消息
-
协调者收到所有参与者反馈的 Ack 消息后,即完成事务的中断
示意图如下:
缺点
- 同步阻塞: 在事务执行过程中,所有参与节点都是事务阻塞型的。参与者占有公共资源时,其他第三方节点访问公共资源则会处于阻塞
- 单点故障:协调者存在单点问题,如果协调者出现故障,参与者将一直处于锁定状态(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
- 脑裂:在阶段2中,如果只有部分参与者接收并执行了Commit请求,会导致节点数据不一致。当协调者向参与者发送Commit请求之后,发生了局部网络异常或者在发送Commit请求过程中协调者发生了故障,导致只有一部分参与者接收到了Commit。而在这部分参与者接收到Commit请求之后就会执行Commit操作。但其他未接收到Commit请求的参与者则无法执行事务提交。于是整个分布式系统化出现了数据不一致的现象。
3PC
3PC,三阶段提交协议,是2PC的改进版本,即将事务的提交过程分为CanCommit、PreCommit、doCommit三个阶段进行处理。
与两阶段提交不同的是,三阶段提交有两个改动点:
- 引入超时机制。(超时提交策略,当第三阶段参与者等待协调者超时后会提交事务,解决参与者同步阻塞问题,同时能在发生单点故障时,继续达成一致)
- 在第一阶段和第二阶段中插入一个准备阶段。(也是为了减少同步阻塞的发生范围)
执行阶段
- 能否提交阶段(CanCommit)
- 预提交阶段(PreCommit)
- 提交阶段(doCommit)
参与角色
- 协调者(coordinator)
- 参与者(participants)
执行流程
阶段1:CanCommit
- 协调者向所有开发者发出包含事务内容的CanCommit请求,询问是否可以提交事务,并等待所有参与者反馈
- 参与者收到CanCommit请求后,如果认为可以执行事务操作,则反馈YES并进入准备状态,否则反馈NO
阶段2:PreCommit
此情况分为两种情况:
- 所有参与者均反馈YES,即执行事务预提交
- 任何一个参与者反馈NO,或等待超时后协调者尚无法收到参与者的反馈,即执行中断事务
事务预提交:
- 协调者向所有参与者发出PreCommit请求,进入准备阶段
- 参与者收到PreCommit请求后,执行事务操作,将Undo和Redo信息记入事务日志中(但不提交事务)
- 各参与者向协调者反馈Ack响应或No响应,并等待最终指令
中断事务:
- 协调者向所有参与者发出abort请求
- 收到协调者的abort请求或者等待超时,参与者均会中断事务
阶段3:doCommit
此情况分为两种情况:
- 所有参与者均反馈Ack响应,即执行真正的事务提交
- 任何一个参与者反馈NO,或等待超时后协调者尚无法收到参与者的反馈,即中断事务
提交事务(所有参与者反馈Ack响应):
- 如果协调者处于工作状态,则向所有参与者发出 doCommit请求
- 参与者收到do Commit请求后,会正式执行事务提交,并释放整个事务期间占用的资源
- 各参与者向协调者反馈Ack完成的消息
- 协调者收到所有参与者反馈的Ack消息后,即完成事务提交
中断事务(任何一个参与者反馈NO):
-
如果协调者处于工作状态,则向所有参与者发出 abort 请求
-
参与者使用阶段1中的Undo信息执行回滚操作,并释放整个事务期间占用的资源
-
各参与者向协调者反馈Ack完成的消息
-
协调者收到所有参与者反馈的Ack消息后,即完成事务中断
示意图如下:
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,会继续进行事务的提交。
优点
- 降低了阻塞范围,在等待超时后协调者或参与者中断事务。避免了协调者单点问题,阶段3中协调者出现问题时,参与者会继续提交事务
缺点
- 脑裂问题依然存在,即在参与者收到PreCommit请求后等待最终指令,如果此时协调者无法和参与者正常通信,会导致参与者继续提交事务,造成数据不一致