上一次我们讲解了分布式事务的 2PC、3PC 。那么这次我们来理一下 TCC 事务。本次还是讲解 TCC 的原理跟 .NET 其实没有关系。
TCC 事务其实是 2PC 的一个扩展。上一次我们说了 2PC ,在二阶段进行事务提交。因为 2PC 基本上是利用数据库的
事务能力进行 commit ,其实这里还有可能出现一种 rollback 情况。 TCC 就是把 2PC 的二阶段细化了,拆分成了 Confirm 跟 Cancel 两个步骤。TCC 是 2PC 的一次进化,TCC 拆分二阶段后已经不局限于数据库事物了,它可以适用于非数据库事物的场景。因为我们的 Cancel 阶段可以进行更加复杂的回滚能力,业务补偿能力。TCC 可以认为是业务层面的2PC 。
下面我们以使用客户积分兑换房间为示例说明一下 TCC 事务。
如果 Confirm 阶段出现异常,TCC 管理器会不断的重试这个阶段,直到成功。因为理论上认为只要 Try 是成功的,那么 Confirm 阶段一定会成功。因为所需要的资源已经在 Try 阶段冻结了。如果 Cancel 阶段出现异常,那么 TCC 管理器也会不断的重试这个阶段来解除冻结的资源。
因为 TCC 有重试机制,所以所有的接口都需要实现幂等,避免多次调用对业务数据产生错误。比如多次扣款,多次下订单等。
因为 TCC 事务在 Try 阶段对资源是完全的提交状态,并没有像 2PC 那样使用数据库事物来对资源进行锁定,所以在并发的时候对资源的修改要格外注意。在处理业务的时候要时刻注意锁定的资源对业务造成的一影响。
TCC 事务在一阶段 Try 的时候失败要运行进行 Cancel 提交。这时候 Cancel 其实是不需要做任何补偿操作,我们称之为空取消。这个时候也要注意,在编写 Cancel 操作的时候要时刻注意到底有没有完成 Try 操作,如果没有完成 Try 操作则要进行空取消。
TCC 按流程上来说是不会出现悬挂情况的。但是有一种特殊情况会造成资源的悬挂。按照正常流程我们的 Try 阶段总是先于 Cancel 执行的。但是由于网络拥堵的问题造成 Try 调用延迟了,TCC 管理器在一定时间没收到 Try 成功响应后会发送 Cancel 调用,这个 Cancel 就有可能在 Try 之前先被调用了。在 Cancel 执行成功后, 这个 Try 请求调用才到达服务,这个时候如果 Try 被执行成功,那么就会造成资源的悬挂。所以当编写 Try 代码的时候同意需要注意是不是已经调用过 Cancel 操作了。
TCC 事务是 2PC 的一种升级。TCC 相对于 2PC 不再依赖于本地数据库事物能力,它可以使用于应用层面的事务。它把 2PC 的提交跟回滚操作明确的抽象成 Confirm 跟 Cancel 。TCC 事务在逻辑上是比较清晰的。但是 TCC 使用起来也有不方便的地方,就是它对代码入侵比较强,比较繁琐。每个业务都要强制拆分成3个方法。而且还要还要注意幂等,空取消,悬挂等问题。
.Net Core with 微服务 - Ocelot 网关
.Net Core with 微服务 - Consul 注册中心
.Net Core with 微服务 - Elastic APM
.Net Core with 微服务 - Consul 配置中心
.Net Core with 微服务 - Polly 熔断降级
.Net Core with 微服务 - 分布式事务 - 2PC、3PC