还不懂分布式事务:带你深入剖析TCC实现原理

云计算 分布式
TCC模型将事务分为Try、Confirm和Cancel三个阶段,使得事务处理更加灵活和可控,保证了数据的一致性,减少了2PC资源锁定时间过长的问题。

TCC概念

常见的分布式事务实现方案有以下几种:两阶段提交(2PC)、三阶段提交(3PC)、TCC(Try-Confirm-Cancel)、补偿事务(Saga)、MQ事务消息等。 由于2PC资源锁定时间较长,性能较差,难以扩展。TCC旨在解决这些问题,TCC是一种补偿型事务模式,通过将每个事务操作分为三个阶段:尝试(Try)、确认(Confirm)和取消(Cancel),不仅优化了事务的执行流程,还提高了系统的整体效率和弹性。

TCC流程

TCC的核心思想在于将事务的每个操作拆分为三个明确的阶段:尝试(Try)、确认(Confirm)和取消(Cancel)。这三个阶段各自承担不同的职责,确保事务在分布式环境中能够安全且一致地执行。

  • Try 阶段

在这个阶段,事务参与者将执行所有必要的检查,并预留必需的资源来保证事务可以顺利完成。例如,在电商场景,当用户尝试购买商品时,系统将在Try阶段检查商品库存,预留所需数量的商品。这个阶段是整个TCC流程中的准备步骤,它不会做任何实际的业务处理,只是确保后续的Confirm阶段可以无障碍地执行。

  • Confirm 阶段

只有当所有参与者的Try阶段成功完成后,才会进入Confirm阶段。在这个阶段,系统将正式执行业务操作,使用在Try阶段预留的资源。继续举例电商场景,如果用户的支付成功,系统将在Confirm阶段正式从库存中扣除商品,完成交易。这一步骤确保了事务的最终一致性和数据的正确性。

  • Cancel 阶段

如果在Try阶段或Confirm阶段中的任何一个环节发生错误,或者某些业务条件未得到满足,整个事务将进入Cancel阶段。在这个阶段,所有已经预留的资源将被释放,所有在Try阶段所做的准备工作将被撤销。例如,如果用户决定取消购买,或者支付未成功,预留的商品库存将被释放,以便其他用户购买。

电商场景介绍

举一个常见的电商场景,用户购买商品,点击支付后。这时候交易系统需要做的操作是:

  1. 更新订单状态为“已支付”
  2. 扣减库存
  3. 增加用户积分

图片图片

电商系统一般采用微服务架构,上述三个操作分别需要调用三个服务完成。流程如下:

  1. 订单服务,更新订单状态为“已支付”
  2. 库存服务,扣减库存
  3. 积分服务,增加用户积分

如果这三个操作在一个服务中,就可以使用本地事务保证订单、库存、积分数据的一致性,但是现在需要调用三个服务,就无法保证数据的一致性了。 如果更新订单状态为“已支付”成功了,但是扣减库存失败了,其他用户就可以继续购买商品,可能会出现超卖问题,这时候就需要引入分布式事务,用来保证分布式系统中数据的一致性。

TCC落地电商场景

把上述电商场景引入TCC事务之后,就变成以下情况。

  • Try阶段实现

Try阶段负责资源的预检查和预留,分别调用三个服务冻结资源:

  1. 订单服务,更新订单状态为“支付中”
  2. 库存服务,冻结库存(库存表中,新增一个冻结库存的字段)
  3. 积分服务,预增加用户积分(积分表,新增一个预增加积分的字段)

图片图片

库存表中,新增了一个冻结库存的字段。在商品详情页面展示剩余库存数量的时候,需要减去冻结库存,防止超卖。

  • Confirm 阶段

当Try阶段都执行成功的时候,就进入Confirm阶段,负责确认资源。流程如下:

  1. 订单服务,更新订单状态为“已支付”
  2. 库存服务,把冻结库存扣减到剩余库存上(update 剩余库存=剩余库存-冻结库存,冻结库存=0)
  3. 积分服务,把预增加积分加到总积分上(udpate 总积分=总积分+预增加积分,预增加积分=0)

图片图片

  • Cancel阶段

当Try阶段任何一个操作失败,就进入Cancel阶段,负责回滚资源。流程如下:

  1. 订单服务,更新订单状态为“已取消”
  2. 库存服务,释放冻结的库存
  3. 积分服务,释放预增加积分

图片图片

TCC问题

上述只是理想情况,在实践的过程中会遇到以下三大问题,影响TCC事务的安全性。

  1. Confirm/Cancel操作失败问题
  2. 空回滚问题
  3. 悬挂问题

针对每个问题,我们思考一下相应的解决方案。

1. Confirm/Cancel操作失败问题在执行完Try阶段之后,进入到Confirm或者Cancel阶段,可能由于服务问题或者网络问题,Confirm或者Cancel操作不一定能成功,通常采用的办法是不断重试,要求Confirm和Cancel接口要支持幂等。

2. 空回滚问题空回滚问题是指Try阶段某个服务的Try操作没有执行成功或者没有执行,进入Cancel阶段,就执行Cancel操作回滚资源,导致数据错乱。 常用的解决方案是Cancel操作前增加事务状态检查。

  • 在 Try 操作开始时,设置事务状态为 TRYING。
  • 如果 Try 操作成功,更新状态为 TRIED。
  • 在 Cancel 操作执行前,检查状态。如果状态不是 TRIED,就不执行 Cancel 操作。

3. 悬挂问题悬挂问题是指 Cancel 操作比 Try 操作先完成。通常出现的原因是由于网络延迟,例如:由于调用Try操作耗时较长,出现网络超时,导致Try操作调用失败,就进入Cancel阶段,执行Cancel操作,而此时Try操作还在执行,最后结果是Cancel操作执行成功后,Try操作又执行成功,出现“悬挂”问题。

解决方案有以下几种:

  1. 与空回滚解决方案类似,Cancel操作前增加事务状态检查。
  • 在 Try 操作开始时,设置事务状态为 TRYING。
  • 如果 Try 操作成功,更新状态为 TRIED。
  • 在 Cancel 操作执行前,检查状态。如果状态不是 TRIED,就不执行 Cancel 操作或者延迟执行。
  1. Try操作引入重试机制

如果调用Try操作超时,可以进行有限次重试,而不是立即执行Cancel操作,可以减少因为网络超时而导致的悬挂问题。这里要求Try接口也要支持幂等操作。

  1. 增加同步机制

可以使用分布式锁来控制Try和Cancel操作的执行顺序。

总结

TCC模型将事务分为Try、Confirm和Cancel三个阶段,使得事务处理更加灵活和可控,保证了数据的一致性,减少了2PC资源锁定时间过长的问题。但是也引入了一些新问题:

  1. 代码侵入严重。Try、Confirm和Cancel三个阶段的事务操作都要耦合在业务逻辑中,耦合性较高。
  2. 设计复杂,开发成本较高。对于TCC引入的幂等操作、空回滚问题、悬挂问题,都需要架构设计的时候考虑相应的解决方案。

需要开发人员自行评估使用成本。

责任编辑:武晓燕 来源: 一灯架构
相关推荐

2018-11-23 09:25:00

TCC分布式事务

2021-06-08 12:46:27

分布式阿里TCC

2024-10-09 14:14:07

2023-05-12 08:02:43

分布式事务应用

2022-06-21 08:27:22

Seata分布式事务

2022-06-27 08:21:05

Seata分布式事务微服务

2022-01-12 10:02:02

TCC模式 Seata

2024-06-12 09:06:48

2024-06-04 10:58:30

2021-03-17 00:05:50

分布式事务提交

2022-07-10 20:24:48

Seata分布式事务

2020-04-28 12:18:08

Seata模式分布式

2019-08-19 10:24:33

分布式事务数据库

2024-01-26 13:17:00

rollbackMQ订单系统

2022-07-20 06:55:10

TCC分布式事务微服务

2021-08-06 08:33:27

Springboot分布式Seata

2023-09-14 15:44:46

分布式事务数据存储

2022-11-24 17:34:04

TCC分布式

2020-03-31 08:05:23

分布式开发技术

2017-07-26 15:08:05

大数据分布式事务
点赞
收藏

51CTO技术栈公众号