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


比如,全局事务在提交/回滚时会调用各TCC服务的Confirm/Cancel业务逻辑 。执行这些Confirm/Cancel业务时,可能会出现如网络中断的故障而使得全局事务不能完成 。
因此,故障恢复机制后续仍然会重新提交/回滚这些未完成的全局事务,这样就会再次调用参与该全局事务的各TCC服务的Confirm/Cancel业务逻辑 。
既然Confirm/Cancel业务可能会被多次调用,就需要保障其幂等性 。
那么,应该由TCC事务框架来提供幂等性保障?还是应该由业务系统自行来保障幂等性呢?
个人认为,应该是由TCC事务框架来提供幂等性保障 。如果仅仅只是极个别服务存在这个问题的话,那么由业务系统来负责也是可以的;
然而,这是一类公共问题,毫无疑问,所有TCC服务的Confirm/Cancel业务存在幂等性问题 。TCC服务的公共问题应该由TCC事务框架来解决;
而且,考虑一下由业务系统来负责幂等性需要考虑的问题,就会发现,这无疑增大了业务系统的复杂度 。
五、TCC事务框架不能盲目的依赖Cancel业务来回滚事务
前文以及提到过,TCC事务通过Cancel业务来对Try业务进行回撤的机制暗含了一个事实:Try操作已经生效 。
也就是说,只有Try操作所参与的RM本地事务已经提交的情况下,才需要执行其Cancel操作进行回撤 。没有执行、或者执行了但是其RM本地事务被rollback的Try业务,是一定不能执行其Cancel业务进行回撤的 。
因此,TCC事务框架在全局事务回滚时,应该根据TCC服务的Try业务的执行情况选择合适的处理机制 。而不能盲目的执行Cancel业务,否则就会导致数据不一致 。
一个TCC服务的Try操作是否生效,这是TCC事务框架应该知道的,因为其Try业务所参与的RM事务也是由TCC事务框架所commit/rollbac的(前提是TCC事务框架接管了Spring的事务管理器) 。
所以,TCC事务回滚时,TCC事务框架可考虑如下处理策略:

  1. 如果TCC事务框架发现某个服务的Try操作的本地事务尚未提交,应该直接将其回滚,而后就不必再执行该服务的cancel业务;
  2. 如果TCC事务框架发现某个服务的Try操作的本地事务已经回滚,则不必再执行该服务的cancel业务;
  3. 如果TCC事务框架发现某个服务的Try操作尚未被执行过,那么,也不必再执行该服务的cancel业务 。
 
总之,TCC事务框架应该保障:
  1. 已生效的Try操作应该被其Cancel操作所回撤;
  2. 尚未生效的Try操作,则不应该执行其Cancel操作 。这一点,不是幂等性所能解决的问题 。如上文所述,幂等性是指服务被执行一次和被执行n(n>0)次所产生的影响相同 。但是,未被执行和被执行过,二者效果肯定是不一样的,这不属于幂等性的范畴 。
 
六、Cancel业务与Try业务并行,甚至先于Try操作完成
这应该算TCC事务机制特有的一个不可思议的陷阱 。
一般来说,一个特定的TCC服务,其Try操作的执行,是应该在其Confirm/Cancel操作之前的 。
Try操作执行完毕之后,Spring容器再根据Try操作的执行情况,指示TCC事务框架提交/回滚全局事务 。然后,TCC事务框架再去逐个调用各TCC服务的Confirm/Cancel操作 。
然而,超时、网络故障、服务器的重启等故障的存在,使得这个顺序会被打乱 。比如:
 
如何设计实现一个通用的分布式事务框架?

文章插图
上图中,假设[B:Try]操作执行过程中,网络闪断,[A:Try]会收到一个RPC远程调用异常 。
A不处理该异常,导致全局事务决定回滚,TCC事务框架就会去调用[B:Cancel],而此刻A、B之间网络刚好已经恢复 。如果[B:Try]操作耗时较长(网络阻塞/数据库操作阻塞),就会出现[B:Try]和[B:Cancel]二者并行处理的现象,甚至[B:Cancel]先完成的现象 。
这种情况下,由于[B:Cancel]执行时,[B:Try]尚未生效(其RM本地事务尚未提交),因此,[B:Cancel]是不能执行的,至少是不能生效(执行了其RM本地事务也要rollback)的 。
然而,当[B:Cancel]处理完毕(跳过执行、或者执行后rollback其RM本地事务)后,[B:Try]操作完成又生效了(其RM本地事务成功提交),这就会使得[B:Cancel]虽然提供了,但却没有起到回撤[B:Try]的作用,导致数据的不一致 。
所以,TCC框架在这种情况下,需要:
  1. 将[B:Try]的本地事务标注为rollbackOnly,阻止其后续生效;
  2. 禁止其再次将事务上下文传递给其他远程分支,否则该问题将在其他分支上出现;
  3. 相应地,[B:Cancel]也不必执行,至少不能生效 。


    推荐阅读