分布式事务TCC
什么是分布式事务
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
分布式事务的优点
- CAP定理
一致性(Consistency) : 客户端知道一系列的操作都会同时发生(生效)
可用性(Availability) : 每个操作都必须以可预期的响应结束
分区容错性(Partition tolerance) : 即使出现单个组件无法可用,操作依然可以完成 - BASE理论
Basically Available(基本可用)
Soft state(软状态)
Eventually consistent(最终一致性)
BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性 - 酸碱平衡:
ACID能够保证事务的强一致性,也就是数据的实时一致,这在本地事务中是没有问题的,在分布式事务中,强一致性会影响分布式系统的性能,因此分布式系统中要遵循Base理论,但是分布式系统在不同业务时对一致性要求也是不同的,就比如交易场景下,这个是需要强一致性的,再比如在发送短信验证码这个时候是可以不需要强一致性的,因此可以遵循Base即可,这就是所谓的酸碱平衡
分布式事务TCC
TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。
三个阶段
- Try 阶段主要是对业务系统做检测及资源预留
- Confirm 阶段主要是对业务系统做确认提交,
- Cancel 阶段是Try 执行失败对预留资源进行回滚操作
Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。
即:只要Try成功,Confirm一定成功
只要Try失败或者异常都会执行 Cancel
普通电商实现订单过程代码
运用TCC实现
具体流程
优缺点
优点: 跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
缺点: 缺点还是比较明显的,在Confirm Cancel中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码。
异常处理
幂等
问题:TC重复调用二阶段解决:事务状态控制记录作为控制手段,只有存在INIT记录时才执行,存在CONFIRMED/ROLLBACKED记录时不再执行
空回滚
问题:TC回滚事务调用二阶段,但一阶段尚未执行解决:事务状态控制记录作为控制手段,无记录时即为空回滚
资源悬挂
问题:TC回滚事务调用二阶段完成空回滚后,一阶段执行成功解决:事务状态控制记录作为控制手段,二阶段发现无记录时插入记录,一阶段执行时检查记录是否存在
共通点
核心的解决方案就是事务状态控制表
幂等控制作为最基础的异常处理手段;资源悬挂的前置条件是空回滚,所以发生空回滚时会插入一条状态为ROLLBACKED的控制记录
有必要使用TCC分布式事务机制来保证各个服务形成一个整体性的事务。
你原本的一个接口,要改造为3个逻辑,Try-Confirm-Cancel。
先是服务调用链路依次执行Try逻辑
如果都正常的话,TCC分布式事务框架推进执行Confirm逻辑,完成整个事务如果都正常的话,TCC分布式事务框架推进执行Confirm逻辑,完成整个事务
如果某个服务的Try逻辑有问题,TCC分布式事务框架感知到之后就会推进执行各个服务的Cancel逻辑,撤销之前执行的各种操作
这就是所谓的TCC分布式事务。
TCC分布式事务的核心思想,说白了,就是当遇到下面这些情况时,
- 某个服务的数据库宕机了
- 某个服务自己挂了
- 那个服务的redis、elasticsearch、MQ等基础设施故障了
- 某些资源不足了,比如说库存不够这些
-
先来Try一下,不要把业务逻辑完成,先试试看,看各个服务能不能基本正常运转,能不能先冻结我需要的资源。
-
如果Try都ok,也就是说,底层的数据库、redis、elasticsearch、MQ都是可以写入数据的,并且你保留好了需要使用的一些资源(比如冻结了一部分库存)。
-
接着,再执行各个服务的Confirm逻辑,基本上Confirm就可以很大概率保证一个分布式事务的完成了。
-
那如果Try阶段某个服务就失败了,比如说底层的数据库挂了,或者redis挂了,等等。
此时就自动执行各个服务的Cancel逻辑,把之前的Try逻辑都回滚,所有服务都不要执行任何设计的业务逻辑。保证大家要么一起成功,要么一起失败。
如果有一些意外的情况发生了,比如说订单服务突然挂了,然后再次重启,TCC分布式事务框架是如何保证之前没执行完的分布式事务继续执行的呢?
所以,TCC事务框架 都是要记录一些分布式事务的活动日志的,可以在磁盘上的日志文件里记录,也可以在数据库里记录。保存下来分布式事务运行的各个阶段和状态。
万一某个服务的Cancel或者Confirm逻辑执行一直失败怎么办呢?
那也很简单,TCC事务框架会通过活动日志记录各个服务的状态。
举个例子,比如发现某个服务的Cancel或者Confirm一直没成功,会不停的重试调用他的Cancel或者Confirm逻辑,务必要他成功!
当然了,如果你的代码没有写什么bug,有充足的测试,而且Try阶段都基本尝试了一下,那么其实一般Confirm、Cancel都是可以成功的!