分布式一致性协议和算法,其中最著名的是二阶段提交协议(2pc),三阶段提交协议(3pc),和paxos算法
在分布式系统中,每个机器节点虽然能知道自身进行事物操作过程中的结果是成功或失败,但却无法直接获取到其他分布式节点的操作结果,因此为了保持事物处理的ACID特性,需要引入称为"协调者"的组件统一调度所有分布式节点的执行罗杰,这些被调度的分布式节点被称为"参与者",协调者负责调度参与者的行为,并最终决定这些参与者是否要把事物真正进行提交,基于这个思想衍生出二阶段提交和三阶段提交两种协议
2PC:
目前绝大部分的关系型数据库都采用二阶段提交协议来完成分布式事物处理的;
二阶段提交协议将事物的提交分成两个阶段来进行
阶段一:提交事物请求
- 事物询问:协调者向所有的参与者发送事物请求,询问是否可以执行事物提交操作,并开始等待各参与者的相应
- 执行事物:各参与这节点执行事物操作,并将Undo(修改前数据镜像,回滚)和Redo(修改前后信息,操作语句)信息记入事物日志中。
- 各参与者向协调者反馈事物询问的相应:如果参与者成功执行了事物操作,那么反馈给协调者yes相应,表示事物可以执行;如果参与者没有成功执行事物,那么就反馈给协调者no相应,表示事物不可以执行
此操作也称为投票阶段 即各参与着投票表明是否要继续执行下去的事物提交操作
阶段二:执行事物提交
在阶段二中,协调者根据个参与者的反馈情况来决定最终是否可以进行事物提交操作,正常情况下包括两种可能
- 执行事物提交:加入协调者获得的所有反馈均为YES,那么就会执行事物提交
- 发送提交请求:协调者向所有参与着节点发出commit请求
- 事物提交:参与者接收到commit请求后,会正式执行事物提交操作,并在完成后释放整个事物执行期间占用的事物资源
- 反馈事物的提交结果:参与者在完成事物提交之后,向协调者发送Ack消息
- 完成事物:协调者接收到所有参与者反馈的ack消息后,完成事物
- 中断事物:假如任何一个参与者向协调者反馈了No相应,或着在等待超时之后,协调者无法接受到所有参与者的反馈请求,那么会中断事物
- 发送回滚请求:协调者向所有参与节点发出Rollback请求。
- 事物回滚:参与者接收到Roolback请求后,会利用其在阶段一中记录的Undo信息来执行事物回滚操作,并在完成回滚hi和释放在整个事物执行期间占用的资源
- 反馈事物回滚消息:参与者在完成事物之后回滚,向协调者发送Ack消息
- 中断事物:协调者接受到所有参与者反馈的Ack消息后,完成事物中断
以上就是二阶段提交过程,——把事物处理分为了投票和执行两个阶段,其核心是对每个事物都采用先尝试后提交的处理方式,因此也可以将二阶段提交看作一个强一致性的算法。
优缺点:
2PC优点:原理简单,方便实现
2PC缺点:同步阻塞,单点问题,脑裂,太过保守
同步堵塞:
最大的问题,2pc执行过程中,所有参与该事物操作的逻辑都处于堵塞状态,也就是说各个参与者在等待其他参与者相应的过程中,将无法进行任何操作
单点问题:
协调者的角色至关重要,一旦协调者出现问题,整个2PC协议将无法运转,更严重的是,如果协调者在阶段二中出现问题的话,那么其他协调者会一直处于锁定事物资源的状态中,而无法继续完成事物操作
数据不一致:2PC的阶段二,即执行事物提交时,当协调者向所有的参与者发送commit请求之后,发生了局部网络异常或者是协调者在尚未发送完commit请求之前发生了自身崩溃,导致最终只有部分参与者收到了commit请求。于是这部分收到了commit请求的参与者就会进行事物的提交,而其他没有收到commit请求的参与者则无法进行事物提交,于是整个分布式系统便会出现数据不一致的现象
太过保守:如果协调者在指示参与者进行事物提交询问的过程中,参与者出现故障而导致协调者始终无法获取到所有参与者的相应信息的话,这是协调者只能依靠其自身的超时机制判断是否需要中断事物,这样的策略显得比较保守,换句话说,2PC协议没有完善的容错机制,任何一个节点的失败都会导致整个事物的失败
3PC:
3PC将提交事物请求的过程一分为二,形成了由CanCommit,PreCommit和do Commit三个阶段组成的事物处理协议
阶段一 :CanCommit
- 事物询问:协调者向所有的参与者发送一个包含事物请求内容的CanCommit请求,询问是否可以执行事物提交操作,并开始等待各参与者的相应
- 各参与者向协调者反馈事物询问的相应:参与者在接收到来自协调者的CanCommit请求后,正常情况下,如果其自身任务可以顺利执行事物,那么会反馈yes相应,并进入预备状态,否则反馈No相应
阶段二:PerCommit
- 执行事物预提交:假如协调者从所有参与者获得的反馈都是yes相应,那么就会执行事物预提交
- 发送预提交请求:协调者向所有参与者节点发送preCommit请求,并进入prepared(准备)阶段
- 事物预提交:参与者接收到preCommit请求后,会执行事物操作,并将Undo和Redo信息记录到
- 各参与者向协调者反馈事物执行的相应:如果参与者成功执行了事物操作,那么就会反馈给协调者ACK相应,同时等待最终的指令:提交(commit)或中止(abort)
- 中断事物:如果任何一个参与者反馈了No相应,或者等待超时后协调者仍无法接收到所有参与者的反馈相应,那么就会中断事物
- 发送中断请求:协调者向所有参与者节点发出abort请求
- 中断事物:无论是收到来自协调者的abort请求,或者是在等待协调者请求的过程中出现超时,参与者都会中断事物
阶段三:doCommit:该阶段进行真正的事物提交,会存在以下两种情况
执行提交:
- 发送提交请求:进入这一阶段,假设协调者处于正常工作状态,并接收到了来自所有参与者的ACK相应,那么他将从"预提交"状态切换到"提交"状态,并向所有的参与者发送doCommit请求。
- 事物提交:参与者收到doCommit请求后,会正式执行事物提交操作,并在完成提交之后释放整个事物执行期间占用的事物资源
- 反馈事物提交结果:参与者在完成事物提交之后,向协调者发送ack消息
- 完成事物:协调这收到所有参与者反馈的ACK消息后,完成事物
中断事物:进入这一阶段,假设协调者处于正常工作状态,并由人一个协调者反馈了No相应,或者在等待超时之后,协调者上无法接收到所有参与者的反馈相应,那么就会中断事物
- 发送中断请求:协调者向所有的参与者节点发送abort请求
- 事物回滚:参与者接受到abort请求后,会利用其在阶段二中记录的Undo信息来执行事物回滚操作,并在完成回滚后释放在整个事物执行期间占用的资源
- 反馈事物回滚结果:参与者在完成事物回滚后,想些协调者发送ACK消息
- 中断事物:协调者接受到所有参与者反馈的ACK消息后中断事物
升级的3PC方案旨在解决这些问题,主要有两个改进:
- 增加超时机制。
- 两阶段之间插入准备阶段。
进入阶段三后,无论协调者出现问题,或者协调者与参与者网络出现问题,都会导致参与者无法接收到协调者发出的do Commit请求或abort请求。此时,参与者都会在等待超时之后,继续执行事务提交。