多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 简介 为了解决两阶段提交协议,提出一个改进版本,三阶段提交协议(3PC). 将协调者和数据库都引入超时机制,以解决在协调者失效的时候,数据库会一直占有资源无法释怀的问题,同时又将准备阶段拆分成了询问和准备两个阶段增加容错概率 # 询问节点 事务协调者给每个数据库发送CanCommit请求,每个数据库如果可以提交就返回YES消息,否则就返回NO消息 大致流程如下: 1. 事务协调者节点向所有数据库发起CanCommit请求,并开始等待各参与者节点的响应 2. 数据库节点收到CanCommit请求之后如果可以提交,则返回YES消息并进入准备阶段.否则返回NO消息 # 准备阶段 事务协调者收到反馈后会有两种情况发生: 1. 数据库返回消息均为yes消息,则执行事务预执行.大致流程如下: 1. 事务协调者节点向所有数据库发起PreCommit请求,并开始等待各参与者节点的响应 2. 数据库节点执行到询问发起为止的所有事务操作,并将undo信息和redo信息写入日志.执行成功后返回ACK应答,并进入等待 2. 数据库返回的消息含有NO消息或者等待超时,则执行事务中断.大致流程是这样: 1. 事务协调者节点向所有数据库发起abort中断请求 2. 数据库节点收到abort请求之后执行事务中断.如果超时之后还没收到事务协调者的任何消息,也执行事务中断动作 # 提交阶段 事务协调者收到反馈后会有两种情况发生: 1. 协调者收到所有ACK应答,则执行事务提交.大致流程如下: 1. 事务协调者节点向所有数据库发起DoCommit请求,并开始等待各参与节点的响应 2. 数据库节点执行commit动作并释放事务占用的资源,之后向事务协调者发送ACK消息应答 3. 事务协调者收到所有数据库的反馈消息后完成事务 2. 协调者没有收到所有ACK应答,则执行事务中断.大致流程如下: 1. 事务协调者节点向所有数据库发起abort中断请求 2. 数据库节点收到abort请求之后执行事务回滚,并向事务协调者发送ACK消息应答 3. 事务协调者收到所有数据库的反馈消息后完成事务中断 # 问题 从三阶段提交的流程来看,已经解决了两阶段的一些问题,但是还是会出现数据不一致问题. 因为当进入第三阶段也就是提交阶段的时候,如果数据库在超时前没有收到DoCommit或abort消息,那么它最终会执行commit操作 试想一下,如果在提交阶段事务协调者没有收到所有ACK应答,那么它会发送abort中断事务的请求.碰巧这时候网络发生了抖动导致一部分数据库没有收到abort消息,那么收到消息的数据库会执行事务中断,而没有收到abort消息的数据库最终执行为commit动作,这就导致数据不一致了