如何设计实现一个通用的分布式事务框架?( 四 )

当然,TCC事务框架也可以简单的选择阻塞[B:Cancel]的处理,待[B:Try]执行完毕后,再根据它的执行情况判断是否需要执行[B:Cancel] 。不过,这种处理方式因为需要等待,所以,处理效率上会有所不及 。
 
同样的情况也会出现在confirm业务上,只不过,发生在Confirm业务上的处理逻辑与发生在Cancel业务上的处理逻辑会不一样 。
TCC框架必须保证:
  1. Confirm业务在Try业务之后执行,若发现并行,则只能阻塞相应的Confirm业务操作;
  2. 在进入Confirm执行阶段之后,也不可以再提交同一全局事务内的新的Try操作的RM本地事务 。
 
七、TCC服务复用性是不是相对较差?
TCC事务机制的定义,决定了一个服务需要提供三个业务实现:Try业务、Confirm业务、Cancel业务 。
可能会有人因此认为TCC服务的复用性较差 。怎么说呢,要是将 Try/Confirm/Cancel业务逻辑单独拿出来复用,其复用性当然是不好的 。
Try/Confirm/Cancel 逻辑作为TCC型服务中的一部分,是不能单独作为一个组件来复用的 。Try、Confirm、Cancel业务共同才构成一个组件,如果要复用,应该是复用整个TCC服务组件,而不是单独的Try/Confirm/Cancel业务 。
八、TCC服务是否需要对外暴露三个服务接口?
不需要 。TCC服务与普通的服务一样,只需要暴露一个接口,也就是它的Try业务 。
Confirm/Cancel业务逻辑,只是因为全局事务提交/回滚的需要才提供的,因此Confirm/Cancel业务只需要被TCC事务框架发现即可,不需要被调用它的其他业务服务所感知 。
换句话说,业务系统的其他服务在需要调用TCC服务时,根本不需要知道它是否为TCC型服务 。
因为,TCC服务能被其他业务服务调用的也仅仅是其Try业务,Confirm/Cancel业务是不能被其他业务服务直接调用的 。
九、TCC服务A的Confirm/Cancel业务中能否调用它依赖的TCC服务B的Confirm/Cancel业务?
最好不要这样做 。
首先,没有必要 。TCC服务A依赖TCC服务B,那么[A:Try]已经将事务上下文传播给[B:Try]了,后续由TCC事务框架来调用各自的Confirm/Cancel业务即可;
其次,Confirm/Cancel业务如果被允许调用其他服务,那么它就有可能再次发起新的TCC全局事务 。如此递归下去,将会导致全局事务关系混乱且不可控 。
TCC全局事务,应该尽量在Try操作阶段传播事务上下文 。Confirm/Cancel操作阶段仅需要完成各自Try业务操作的确认操作/补偿操作即可,不适合再做远程调用,更不能再对外传播事务上下文 。
综上所述,本文倾向于认为,实现一个通用的TCC分布式事务管理框架,还是相对比较复杂的 。一般业务系统如果需要使用TCC事务机制,并不推荐自行设计实现 。
这里,给大家推荐一款开源的TCC分布式事务管理器ByteTCC
https://github.com/liuyangming/ByteTCC
ByteTCC基于Try/Confirm/Cancel机制实现,可与Spring容器无缝集成,兼容Spring的声明式事务管理 。提供对dubbo框架、Spring Cloud的开箱即用的支持,可满足多数据源、跨应用、跨服务器等各种分布式事务场景的需求 。




推荐阅读