2. 分布式事务
假设多个服务要触发一系列连续的操作,每个操作涉及到不同的数据库,且这一套操作要么全部成功,要么全部失败,那么分布式事务就是保证这一套发生于不同服务的、涉及不同数据库的操作是一个事务操作,构成一个全局事务
假设你要创建一个申请购买电脑的工单,存在工单处理、资产审批、资产购买这三个微服务,且对应三个库,那么就必须使得下面一套流程遵循事务特性:修改审批状态为通过->修改资产购买状态为完成->修改工单状态为结束
2.1 两阶段提交(2 Phase Commit)
2.1.1 定义
通过引入单点协调者来协调多个需要一次完成的多个事务,通过协调者保证这一套事务的成功提交
2.1.2 流程
- 投票阶段
- 协调者向所有参与者发出投票请求
- 参与者收到后开始执行事务,但不提交,如果
- 执行成功,则返回可以提交
- 执行失败,则返回需要回滚
- 提交阶段协调者如果
- 收到所有反馈,且
- 全为成功,则发出提交请求至参与者,参与者收到后进行commit,并返回ack
- 不全为成功,则发出回滚请求至参与者,参与者收到后进行rollback,并返回ack
- 在规定时间内未收到所有反馈
向所有参与者发出回滚请求,参与者收到后进行rollback,并返回ack
2.1.3 故障分析
- 只有参与者宕机
- 在投票阶段宕机(非阻塞)
协调者会超时,之后让其他协调者rollback - 在提交阶段宕机(非阻塞)
由于协调者会将二阶段做出的决策写入日志,当此参与者恢复时,可以通过询问协调者得到此决策,来决定时回滚还是提交,注意,这里协调者不会阻塞等待参与者恢复
- 只有协调者宕机
- 在投票阶段宕机(非阻塞)
所有参与者会推选出新的协调者 - 在提交阶段宕机
- 如果没有任何参与者收到协调者的决策
所有参与者推选出新的协调者来重启2PC - 如果有参与者收到了协调者的决策(非阻塞)
收到信息的参与者可以将决策传播给其他参与者,完成提交或回滚
- 参与者和协调者均宕机
- 均在第一阶段宕机(非阻塞)
剩余的参与者推选新的协调者 - 参与者第一阶段宕机&协调者第二阶段宕机
- 如果没有任何剩余活跃参与者收到协调者的决策(非阻塞)
所有活跃参与者推选出新的协调者来重启2PC - 如果有剩余活跃参与者收到了协调者的决策(非阻塞)
收到信息的参与者可以将决策传播给其他参与者,完成提交或回滚
- 参与者第二阶段宕机&协调者第一阶段宕机
不存在 - 均在第二阶段宕机(阻塞!!!)这里考虑下面时序:协调者向参与者A发出提交请求 -> 协调者宕机 -> 参与者A收到提交请求并写盘 -> 参与者A宕机那么此时如果剩余的活跃的参与者推选出新的协调者,决定回滚, 之后原协调者恢复发出提交,这样两者就产生冲突!上面时序尽管苛刻,但是对于参与者和协调者均在第二阶段宕机这个情况,从剩余活跃的参与者角度来看,并不清楚
- 是否协调者发出提交/回滚请求
- 是否宕机的参与者收到了提交/回滚请求
- 这样,剩余的参与者只能等待协调者恢复
2.1.4 缺点
- 单点故障
如果协调者单点出现问题,那么整个事务就失去了原子性保证,可以通过推选新的协调者来重新执行一次2PC流程 - 同步阻塞
- 2PC整个阶段,协调者和参与者都要保持同步
- 故障分析中最后一个例子,会使得所有活跃的参与者陷入阻塞状态
2.2 三阶段提交(3 Phase Commit)
2.2.1 定义
同样使用单点协调者,相较于2PC引入了多了一个阶段,用于解决2PC中协调者第二阶段宕机,所有参与者阻塞的问题
2.2.2 流程
- CanCommit阶段
- 协调者发出CanCommit请求
- 参与者收到后,尝试获取数据库锁,检查执行事务所需资源是否就绪,如果
- 就绪
返回ack - 未就绪
返回nack
- PreCommit阶段
- 协调者如果收到所有ack,则发出预提交请求
- 参与者收到后,执行事务,但不提交,如果
- 执行成功
返回ack - 执行失败
返回nack
- DoCommit阶段
- 协调者如果收到事务执行结果均为成功
发出commit请求,所有参与者收到后commit,并ack - 存在失败
发出rollback请求,所有参与者收到后rollback,并ack
2.2.3 故障分析
这里仅对协调者分析
- CanCommit阶段宕机
参与者重选协调者 - PreCommit阶段宕机
代表所有参与者状态正常,且没有或只有一部分参与者执行了事务,这时参与者会推选新的协调者接着此阶段继续执行 - doCommit阶段宕机
所有参与者此时处于执行事务但未提交状态,只要有任意参与者收到commit则进行提交,如果没有参与者收到,则超时后进行提交
2.2.4 为何3PC可以解决2PC问题
2PC的问题在于,参与者不清楚协调者的状态,只有协调者直到所有参与者的状态。而3PC通过将2PC的第一阶段拆分成CanCommit和PreCommit,之后由CanCommit保证协调者预备状态良好,由PreCommit告知参与者协调者意欲完成这次提交,这样就可以让参与者遇到协调者
- 在第三阶段宕机时可以有充分保证在超时状态下提交
- 在第二阶段宕机时,此时未进行提交,可以重选协调者继续流程
2.2.5 缺点
- 在协调者宕机时,由于网络分片问题,可以会推举出多个新的协调者,当时数据不一致
- 多了一个阶段,使得网络延迟增大,使得全局事务阻塞时间也增大
2.3 TCC(Try Confirm Cancel)
"整体流程类似于2PC,但 TCC 是位于用户代码层面,而不是在基础设施层面,这为它的实现带来了较高的灵活性,可以根据需要设计资源锁定的粒度"