🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### TCC模型(补偿事务) TCC(Try-Confirm-Cancel)分布式事务模型相对于 XA 等传统模型,其特征在于它不依赖资源管理器(RM)对分布式事务的支持,而是通过对业务逻辑的分解来实现分布式事务。 TCC 模型认为对于业务系统中一个特定的业务逻辑,其对外提供服务时,必须接受一些不确定性,即对业务逻辑初步操作的调用仅是一个临时性操作,调用它的主业务服务保留了后续的取消权。如果主业务服务认为全局事务应该回滚,它会要求取消之前的临时性操作,这就对应从业务服务的取消操作。而当主业务服务认为全局事务应该提交时,它会放弃之前临时性操作的取消权,这对应从业务服务的确认操作。每一个初步操作,最终都会被确认或取消 **TCC 分布式事务模型需要业务系统提供三段业务逻辑:** 1. 初步操作 Try:完成所有业务检查,预留必须的业务资源。 2. 确认操作 Confirm:真正执行的业务逻辑,不作任何业务检查,只使用 Try 阶段预留的业务资源。因此,只要 Try 操作成功,Confirm 必须能成功。另外,Confirm 操作需满足幂等性,保证一笔分布式事务有且只能成功一次。 3. 取消操作 Cancel:释放 Try 阶段预留的业务资源。同样的,Cancel 操作也需要满足幂等性 ![](https://img.kancloud.cn/10/bf/10bff1c4981a19b9e034079c21cbbfdb_654x644.png) ### TCC 分布式事务模型包括三部分: 1.主业务服务:主业务服务为整个业务活动的发起方,服务的编排者,负责发起并完成整个业务活动。 2.从业务服务:从业务服务是整个业务活动的参与方,负责提供 TCC 业务操作,实现初步操作(Try)、确认操作(Confirm)、取消操作(Cancel)三个接口,供主业务服务调用。 3.业务活动管理器:业务活动管理器管理控制整个业务活动,包括记录维护TCC 全局事务的事务状态和每个从业务服务的子事务状态,并在业务活动提交时调用所有从业务服务的Confirm 操作,在业务活动取消时调用所有从业务服务的Cancel操作 **TCC 分布式事务流程如下:** 1. 主业务服务首先开启本地事务; 2. 主业务服务向业务活动管理器申请启动分布式事务主业务活动; 3. 然后针对要调用的从业务服务,主业务活动先向业务活动管理器注册从业务活动,然后调用从业务服务的 Try 接口; 4. 当所有从业务服务的 Try 接口调用成功,主业务服务提交本地事务;若调用失败,主业务服务回滚本地事务; 5. 若主业务服务提交本地事务,则 TCC 模型分别调用所有从业务服务的 Confirm 接口;若主业务服务回滚本地事务,则分别调用 Cancel 接口; 6. 所有从业务服务的 Confirm 或 Cancel 操作完成后,全局事务结束 #### 原子性 TCC 模型也使用 2PC 原子提交协议来保证事务原子性。Try 操作对应 2PC 的一阶段准备(Prepare);Confirm 对应 2PC 的二阶段提交(Commit),Cancel 对应 2PC 的二阶段回滚(Rollback),可以说 TCC 就是应用层的 2PC。 #### 隔离性 TCC 分布式事务模型仅提供两阶段原子提交协议,保证分布式事务原子性。事务的隔离交给业务逻辑来实现。 隔离的本质是控制并发,防止并发事务操作相同资源而引起的结果错乱。 举个例子,比如金融行业里管理用户资金,当用户发起交易时,一般会先检查用户资金,如果资金充足,则扣除相应交易金额,增加卖家资金,完成交易。如果没有事务隔离,用户同时发起两笔交易,两笔交易的检查都认为资金充足,实际上却只够支付一笔交易,结果两笔交易都支付成功,导致资损。 可以发现,并发控制是业务逻辑执行正确的保证,但是像两阶段锁这样的并发访问控制技术要求一直持有数据库资源锁直到整个事务执行结束,特别是在分布式事务架构下,要求持有锁到分布式事务第二阶段执行结束,也就是说,分布式事务会加长资源锁的持有时间,导致并发性能进一步下降。 因此,TCC 模型的隔离性思想就是通过业务的改造,在第一阶段结束之后,从底层数据库资源层面的加锁过渡为上层业务层面的加锁,从而释放底层数据库锁资源,放宽分布式事务锁协议,提高业务并发性能。 还是以上面的例子举例: 1.第一阶段:检查用户资金,如果资金充足,冻结用户本次交易资金,这笔资金被业务隔离,不允许除本事务之外的其它并发事务动用。 2.第二阶段:扣除第一阶段预冻结的用户资金,增加卖家资金,完成交易。 采用业务加锁的方式,隔离用户冻结资金,在第一阶段结束后直接释放底层资源锁,该用户和卖家的其他交易都可以立刻并发执行,而不用等到整个分布式事务结束,可以获得更高的并发交易能力。 #### 一致性 再来看看 TCC 分布式事务模型下的一致性实现。与 XA 协议实现一致性第一层语义类似,通过原子性保证事务的原子提交、业务隔离性控制事务的并发访问,实现分布式事务的一致性状态转变。 至于第二层语义:事务的中间状态不能被观察到。我们来看看,在 SOA 分布式应用环境下是否是必须的。 还是以账务服务举例。转账业务(用户 A  用户 B),由交易服务和账务服务组成分布式事务,交易服务作为主业务服务,账务服务作为从业务服务,账务服务的 Try 操作预冻结用户 A 的资金;Commit 操作扣除用户 A 的预冻结资金,增加用户 B 的可用资金;Cancel 操作解冻用户 A 的预冻结资金。 当账务服务执行完 Try 阶段后,交易主业务就可以 Commit 了,然后由 TCC 框架调用账务的 Commit 阶段。在账务 Commit 阶段还没执行结束的时候,用户 A 可以查询到自己的余额已扣除,但是,此时用户 B 的可用资金还没增加。 从系统的角度来看,确实有问题与不确定性。在第一阶段执行结束到第二阶段执行结束之间,有一段时间的延时,在这段时间内,看似任何用户都不享有这笔资产。 但是,从用户的角度来考虑这个问题的话,这个时间间隔可能就无所谓或者根本就不存在。特别是当这个时间间隔仅仅是几秒钟,对于具体沟通资产转移的用户来讲,这个过程是隐蔽的或确实可以接受的,且保证了结果的最终一致性。 当然,对于这样的系统,如果确实需要查看系统的某个一致性状态,可以采用额外的方法实现。 一般来讲,服务之间的一致性比服务内部的一致性要更加容易弱化,这也是为什么 XA 等直接在资源层面上实现通用分布式事务的模型会注重一致性的保证,而当上升到服务层面,服务与服务之间已经实现了功能的划分,逻辑的解耦,也就更容易弱化一致性,这就是 SOA 架构下 BASE 理论的最终一致性思想。 BASE 理论是指 BA(Basic Availability,基本业务可用性);S(Soft state,柔性状态);E(Eventual consistency,最终一致性)。该理论认为为了可用性、性能与降级服务的需要,可以适当降低一点一致性的要求,即“基本可用,最终一致”。 业内通常把严格遵循 ACID 的事务称为刚性事务;而基于 BASE 思想实现的事务称为柔性事务。柔性事务并不是完全放弃了 ACID,仅仅是放宽了一致性要求:事务完成后的一致性严格遵循,事务中的一致性可适当放宽;