分布式事务-Saga事务模型和TCC事务模型

bluetears 2019-04-26

在微服务架构中,通常一个业务操作,伴随着多个子任务,比如创建订单业务操作,涉及到下单、扣减库存、下发仓储物流、邮件/短信通知等等。那如何保证实现一致性呢?

分布式事务-Saga事务模型和TCC事务模型

Saga 事务模型

又称为Long-running-transaction(长事务),核心思想是把一个长事务分为多个本地事务来完成,由一个Process Manager 统一协调。如果成功,则继续往下执行,如果失败,则调用补偿操作。

每个业务都至少需要实现正向、反向两个接口。

我们看如下一个业务场景。在购买旅游套餐业务操作涉及到三个操作,他们分别是预定车辆,预定宾馆,预定机票,他们分别属于三个不同的远程接口。可能从我们程序的角度来说他们不属于一个事务,但是从业务角度来说是属于同一个事务的。

分布式事务-Saga事务模型和TCC事务模型

他们的执行顺序如上图所示,所以当发生失败时,会依次进行取消的补偿操作。

因为长事务被拆分了很多个业务流,所以 Saga 事务模型最重要的一个部件就是流程管理器(Process Manager)。

在执行到第3步时,发生了失败,回退的过程也比较复杂,特别是子业务比较多的场景。

如何实现数据的一致性呢?如下罗列了一些方案。

1. 建立一个定时任务去检查数据的完整性,如果第3步失败了,定时任务会检测到并修复数据。

2. 如果失败,可以发生消息到MQ,消费者根据状态,去重试,或者执行回退操作。同时,也可以进一步检查数据的一致性。

3. 本地操作日志或DB日志。

TCC 事务模型

TCC(Try Confirm Cancel)事务模型的思想和2PC提交有点类似。下图是TCC和2PC(XA)的对比。

分布式事务-Saga事务模型和TCC事务模型

1) 在阶段1:

在2PC(XA)中,各个RM准备提交各自的事务分支,事实上就是准备提交资源的更新操作(insert、delete、update等);而在TCC中,是主业务活动请求(try)各个从业务服务预留资源。

2) 在阶段2:

2PC(XA)根据第一阶段每个RM是否都prepare成功,判断是要提交还是回滚。如果都prepare成功,那么就commit每个事务分支,反之则rollback每个事务分支。

TCC中,如果在第一阶段所有业务资源都预留成功,那么confirm各个从业务服务,否则取消(cancel)所有从业务服务的资源预留请求。

TCC两阶段提交与2PC/XA两阶段提交的区别是:

  • 2PC是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。
  • TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。

TCC 把相关的操作,从数据库转移到业务中,以此降低数据库的压力,并且不需要加速,性能也得到了提升。

TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:

  • Try 阶段主要是对业务系统做检测及资源预留。
  • Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
  • Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。

举个例子,假入 Bob 要向 Smith 转账,思路大概是:

我们有一个本地方法,里面依次调用:

1、首先在 Try 阶段,要先调用远程接口把 Smith 和 Bob 的钱给冻结起来。

2、在 Confirm 阶段,执行远程调用的转账的操作,转账成功进行解冻。

3、如果第2步执行成功,那么转账成功,如果第二步执行失败,则调用远程冻结接口对应的解冻方法 (Cancel)。

TCC的优势:

在业务层处理,降低数据库的压力;

比2PC性能好很多,没有真正在数据库加锁;

TCC的问题:

增加业务复杂度,需要提供相应的Try、Confirm、Cancel接口;

需要提供幂等性实现;

TCC有很多的开源实现方案涌现出来,如:tcc-transaction、ByteTCC、spring-cloud-rest-tcc。

相关推荐