Skip to content

分布式事务

反向补偿

在分布式情况下,假如存在 A 同时调用 B、C多个微服务。假如 B 服务事务正常执行并提交,但是 C 事务提交失败,此时 B 和 C都需要回滚。

而 MySQL 的事务回滚是通过 redo log 机制来实现的,保证事务的持久化和一致性。

但是在分布式,使用了分布式事务的情况下,是通过一条更新SQL,还原原本的数据。

一文搞明白分布式事务解决方案!真的 so easy!

分布式事务,原理简单,写起来全是坑! - 掘金

分布式事务解决方案

2PC - 两阶段提交

  1. prepare - 准备阶段

    各个参与者本地事务执行完成,向事务协调者提交本地事务状态。

  2. commit/rollback - 提交/回滚阶段

    • 如果所有参与者本地事务都执行完成,事务协调者则触发全体提交。

    • 如果有一个参与者的本地事务执行失败,事务协调者则触发全体回滚。

缺点

image.png

  1. 同步阻塞

    第一阶段之后,所有本地资源都要处于事务的锁定状态。

  2. 单点故障

    事务协调者如果挂掉,整个事务无法进行。

  3. 数据不一致

    如果网络故障影响到事务协调者下发命令,可能导致事务参与者的数据不一致问题。

3PC - 三阶段提交

3PC 的引入是为了解决 2PC 同步阻塞和减少数据不一致的情况。

3PC比2PC就多了一个询问阶段。

  1. 询问准备

  2. 预提交 - prepare

  3. 提交/回滚 - commit/rollback

image.png

加入一个询问节点,就像是在事务开始之前询问各个事务参与者的状态。保证大家都能达到起跑点,然后再开始事务的准备和提交。

就是在2PC基础上,增加一个保证各个事务参与者准备完成的阶段。

image 2

不管是 2PC 还是 3PC 都是依赖于数据库的事务提交和回滚。

TCC-补偿事务

TCC (Try-Confirm-Cancel)

TCC与2PC的思想很相似,事务处理流程也很相似,但2PC是应用于在DB层面,TCC则可以理解为在应用层面的2PC,是需要我们编写业务逻辑来实现。

TCC 分为两个阶段。

  1. 第一阶段是资源检查预留阶段即 Try。

  2. 第二阶段是 Confirm 或 Cancel,如果是提交的话就是执行真正的业务操作,如果是回滚则是执行预留资源的取消,恢复初始状态。

image.png

TCC问题

image.png

  1. 幂等实现

    TCC的三个方法都会有重试机制,所以方法需要实现幂等性。

  2. 空回滚

    如果try由于网络问题超时未执行,触发了Cancel方法。要确保Cancel在try未执行的情况正确执行。

  3. 防悬挂

    指 Try 方法由于网络阻塞超时触发了事务管理器发出了 Cancel 命令,但是执行了 Cancel 命令之后 Try 请求到了。

    本来事务都结束了,但是执行了try,后续也不会再执行。

    需要我们在空回滚的情况下,记录一下已经Cancel,防止再执行try。

本地消息表+补偿事务

本地消息表的方案核心就是将分布式事务拆分为本地事务来执行。

通过本地事务来保证最终一致性。

image.png

  1. 事务A 写消息到本地消息表,消息状态为未完成。定时轮训消息状态,如果未成功会继续发给MQ。

  2. 通过MQ通知事务B去消费业务数据,事务B本地事务完成后,回调事务A的方法修改消息状态为已完成。

事务消息+补偿事务

利用RocketMQ的事务消息,既保证本地事务执行成功,又能保证事务消息能够投递成功。

如果其他事务执行失败,可以通过消息触发本地事务的回滚(补偿逻辑)。

image 6

Seata

Seata分布式事务