一致性协议主要思想
当一个事务操作需要跨越很多分布式节点的时候,为了保持事务的ACID,需要引入一个“协调者(Coordinator)”的组件来统一调度所有分布式节点的逻辑,被调度的节点被称为“参与者(Participant)”
协调者负责调度参与者的行为,并决定参与者是否要把事务真正的进行提交。
二阶段提交协议 2PC
2PC(Two-Phase Commit)是基于分布式系统架构下的所有节点在进行事务处理过程中能保持原子性和一致性设计的算法。用来保证分布式系统的一致性。目前绝大部分关系型数据库都是采用二阶段提交协议来完成分布式事务处理的。二阶段提交协议被广泛应用在许多分布式系统中。
协议说明
二阶段协议就是将事务提交的过程分成了两个部分。
阶段一:投票阶段
- 协调者向所有参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待参与者的反应
- 参与者节点执行事务操作,将Undo、Redo信息记入事务日志
- 参与者成功执行了事务操作,就反馈给协调者Yes响应,表示事务可以执行。反之返回No,事务不可执行。
第一阶段是参与者投票表面是否要继续执行接下去的事务提交操作,所以叫”投票阶段“
阶段二:执行阶段
第二阶段根据参与者的反馈来决定最终是否进行事务提交操作,一般有两种情况
第一种情况:所有的参与者都反馈Yes响应
- 协调者向所有参与者节点发出commit请求
- 参与者接收到Commit请求后,执行事务提交操作,完成之后释放事务资源
- 参与者完成事务提交之后,向协调者发送Ack消息
- 协调者收到所有参与者的Ack消息之后,完成事务
第二种情况:有任何一个参与者反馈了No响应,或者等待超时,则中断事务
- 协调者向所有参与者节点发出Rollback请求
- 参与者收到Rollbackq请求,利用Undo信息执行事务回滚操作,完成后释放资源
- 参与者完成事务回滚之后,向协调者发送Ack消息
- 协调者收到所有参与者的Ack消息,完成事务中断
如果两个参与者能够执行事务的提交,先执行事务操作,然后返回YES,如果没有成功执行事务操作,就返回NO。
如果两个参与者能够执行事务的提交,先执行事务操作,然后返回YES,如果没有成功执行事务操作,就返回NO。
当协调者接收到所有的参与者的反馈之后,开始进入事务提交阶段。如果所有参与者都返回YES,那就发送COMMIT请求,如果有一个人返回NO,那就返送roolback请求。
缺点
- 同步阻塞:在第二阶段中,所有参与者与该事务的逻辑都处于阻塞状态,在等待其他参与者的过程中,无法进行其他操作
- 单点问题:协调者一旦出现问题,2PC将无法运转,更严重的是,如果在第二阶段出现问题的话,其他参与者将会一直处于锁定事务资源的状态中。
- 过于保守:2PC没有设计完善的容错机制,任意一个节点失败都会导致全局事务的失败
- 数据不一致:在第二阶段commit的过程中,如果有的节点出现问题如局部网络异常的,导致只有部分参与者收到了commit请求,那么之后收到commit请求的参与者进行事务提交,其他则不会,导致分布式系统出现数据不一致的情况。
三阶段提交协议 3PC
因为2PC的种种问题,改进除了3PC(Three-Phase Commit)三阶段提交。将2PC的第一阶段分为了两部分。
协议说明
阶段一:CanCommit
协调者询问事务是否可以执行,这一步不会锁定资源
- 协调者向所有的参与者发送一个包含事务内容的canCommit请求,询问是否可以执行事务提交操作,并开始等待
- 参与者收到后,认为可以顺利执行事务,就反馈Yes,进入预备状态。否则返回No
阶段二:PreCommit
PreCommit阶段协调者会更具参与者的反馈情况来决定是否可以进行事务的协调者发送事务执行指令,这一步锁住资源。如果由于网络原因参与者在后面没有收到协调者的命令,他也会执行commit
PreCommit操作,通常有两种可能。
第一种情况:协调者收到的都是Yes反馈,进行事务的预提交
- 协调者向所有的参与者发出PreCommit请求,并进入Prepare阶段
- 参与者接收到PreCommit请求后,会执行事务操作,将Undo和Redo信息记录到事务日志中。
- 参与者成功执行了实务操作,就会反馈给协调者Ack响应,同时等待最终指令:提交(commit)或者终止(abort)
第二种情况:任何一个参与者给协调者反馈No响应,或者任何参与者反馈超时,会中断事务
- 协调者向所有参与者发送abort请求
- 无论是收到协调者的abort请求,或者等待协调者请求过程中出现超时,参与者都会中断事务
阶段三:doCommit
真正进行事务提交,会出现两种可能。
第一种情况:执行提交
- 进入这一阶段,假设协调者处于工作状态,收到了参与者的Ack响应,那么就从”预提交“状态转到”提交状态“,向所有参与者发送doCommit请求
- 参与者收到doCommit请求,正式执行事务提交操作,提交完成释放事务资源
- 参与者完成事务提交之后,向协调者发送Ack消息
- 协调者接收到所有参与者反馈的Ack信息后,完成事务
第二种情况:中断事务
协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
1. 协调者向所有的参与者发送abort请求
2. 参与者接收到abort请求,利用Undo信息执行事务回滚,完成后释放事务资源
3. 参与者完成回滚之后向协调者发送Ack信息。
4. 协调者接收到所有的参与者Ack信息之后,中断事务
参与者在第三阶段就算没有接收到doCommit或者是abort请求,还是会带等待超时之后继续进行事务提交。
优缺点
相对于2PC,3PC主要解决的单点故障问题,并减少阻塞,因为一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时,会在等待超时之后,会继续进行事务的提交。
所以,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。