柔性事务解决方案:TCC
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/676be9f827b011c9c2e6139ba2edeb07.png)
实现
一个完整的业务活动由一个主业务服务与若干从业务服务组成
主业务服务负责发起并完成整个业务活动
从业务服务提供TCC型业务操作
业务活动管理器控制业务活动的一致性,它登记业务活动中的操作, 并在
业务活动提交时确认所有的TCC型操作的confirm操作,在业务活动取消
时调用所有TCC型操作的cancel操作
成本
实现TCC操作的成本
业务活动结束时confirm或cancel操作的执行成本
业务活动日志成本
适用范围
强隔离性、严格一致性要求的业务活动
适用于执行时间较短的业务(比如处理账户、收费等业务)
用到的服务模式
TCC操作、幂等操作、可补偿操作、可查询操作
方案特点
不与具体的服务框架耦合(在RPC架构中通用)
位于业务服务层,而非资源层
可以灵活选择业务资源的锁定粒度
TCC事务注意事项
1、业务操作分两阶段完成:
接入 TCC 前,业务操作只需要一步就能完成。但是在接入 TCC 之后,需要考虑如何将其分成两个阶段完成:把资源的检查和预留放在一阶段的 Try 操作中进行,把真正的业务操作的执行放在二阶段的 Confirm 操作中进行。
以下举例说明业务模式如何分成两阶段进行设计,举例场景:“账户 A 的余额中有 100 元,需要扣除其中 30 元”。
在接入 TCC 之前,用户编写 SQL:“update 账户表 set 余额 = 余额 -20 where 账户 = A”,便能一步完成扣款操作。
在接入 TCC 之后,就需要考虑如何将扣款操作分成两步完成:
Try 操作:资源的检查和预留。
在扣款场景,Try 操作要做的事情就是先检查 A 账户余额是否足够,再冻结要扣款的 30 元(预留资源);此阶段不会发生真正的扣款。
Confirm 操作:执行真正业务的提交。
在扣款场景下,Confirm 阶段做的事情就是发生真正的扣款,把 A 账户中已经冻结的 30 元钱扣掉。
Cancel 操作:预留资源的释放。
在扣款场景下,扣款取消,Cancel 操作执行的任务是释放 Try 操作冻结的 30 元钱,使 A 账户回到初始状态。
2、并发控制
用户在实现 TCC 时,应当考虑并发性问题,将锁的粒度降到最低,以最大限度提高分布式事务的并发性。
以下还是以 A 账户扣款为例,“账户 A 上有 100 元,事务 T1 要扣除其中的 30 元,事务 T2 也要扣除 30 元,出现并发”。
在一阶段 Try 操作中,分布式事务 T1 和分布式事务 T2 分别冻结资金的那一部分资金,相互之间无干扰。这样在分布式事务的二阶段,无论 T1 是提交还是回滚,都不会对 T2 产生影响,这样 T1 和 T2 可以在同一笔业务数据上并行执行。
3、允许空回滚
如下图所示,事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因为丢包而导致的网络超时。此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,而 Cancel 操作调用未出现超时。
TCC 服务在未收到 Try 请求的情况下收到 Cancel 请求,这种场景被称为空回滚。空回滚在生产环境经常出现,用户在实现 TCC 服务时,应允许空回滚的执行,即收到空回滚时返回成功。
4、防悬挂控制
如下图所示,事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会出现因网络拥堵而导致的超时。此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 调用未超时。在此之后,拥堵在网络上的一阶段 Try 数据包被 TCC 服务收到,出现二阶段 Cancel 请求比一阶段 Try 请求先执行的情况,此 TCC 服务在执行晚到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel,造成 TCC 服务悬挂。
用户在实现 TCC 服务时,要允许空回滚,但是要拒绝执行空回滚之后 Try 请求,要避免出现悬挂。
5、幂等控制
无论是网络数据包重传,还是异常事务的补偿执行,都会导致 TCC 服务的 Try、Confirm 或者 Cancel 操作被重复执行;用户在实现 TCC 服务时,需要考虑幂等控制,即 Try、Confirm、Cancel 执行一次和执行多次的业务结果是一样的。
1、所有的参与者都需要实现三个方法
2、事务活动管理器