微服务学习笔记6

84 阅读4分钟

Sagas长事务模式

在Sagas事务模型中,一个长事务是由一个预先定义好执行顺序的子事务集合和它们对应的补偿子事务集合所组成。典型的一个完整的交易由T1、T2、……、Tn等多个业务活动组成,每个业务活动可以是本地操作或者是远程操作,而每个业务活动都有对应的取消活动C1、C2、……、Cn。所有的业务活动在Sagas事务下要么全部成功,要么全部回滚,不存在中间状态。

我们需要设计一种存储模型来保存执行上下文并通过该存储模型来索引到对应的服务。存储模型中包含了两个内部结构,一个是完成的任务,一个是等待执行的任务。如果成功就会将任务向前执行,如果失败就会向后执行。实现上的一种思路是采用队列(Queue)和栈(Stack)数据结构,一方面使用队列来向前执行,另一方面使用栈来向后执行。

每个业务活动都是一个原子操作,而且需要每个业务活动均提供确认和取消操作,当任何一个业务活动发生错误时,按照执行的逆向顺序,实时执行取消操作,进行事务回滚。

TCC模式

TCC(Try/Confirm/Cancel)模式是对补偿模式的优化。

在TCC模式中,一个完整的TCC业务由一个主服务和若干个从服务组成,主服务发起并完成整个业务流程。TCC 模式要求从服务提供三个接口:Try、Confirm、Cancel。基于TCC模式的服务抽象如图5-24所示。

(1)Try接口:完成所有业务规则检查,预留业务资源。

(2)Confirm接口:真正执行业务,其自身不作任何业务检查,只使用Try阶段预留的业务资源,同时该操作需要满足幂等性。

(3)Cancel接口:释放Try阶段预留的业务资源,同样也需要满足幂等性。

我们还是通过订单系统的示例来进一步理解TCC模式的设计思想。订单系统拆分成订单下单和订单支付两个场景:

(1)Try阶段:尝试执行业务。在该阶段中,一方面要完成所有业务检查,如针对该次订单下单操作,需要验证商品的可用性以及用户账户中是否有足够的余额;另一方面,也需要预留业务资源,如把用户账户中的部分余额进行冻结用于支付该订单,确保不会出现其他并发进程扣减了账户的余额而导致在后续的真正支付操作过程中,账户可用余额不够的情况。 

 (2)Confirm阶段:执行业务。在该阶段中真正执行业务,如果Try阶段一切正常,则执行下单操作并扣除用户账户中的支付金额。 

 (3)Cancel 阶段:取消执行业务。在该阶段中释放 Try 阶段预留的业务资源,如果Try阶段部分成功,如商品可用且正常下单,但账户余额不够而冻结失败,则需要对产品下单做取消操作,释放被占用的该商品。

在以上流程中,如果订单服务和支付服务中某个服务Try操作失败,那么可以向TCC服务框架提交Cancel操作,或者什么也不做由该服务自己超时处理。需要说明的是为保证业务成功率,Confirm/Cancel操作过程都需要支持重试,这也意味着Confirm/Cancel的实现必须具有幂等性。如果业务服务向TCC服务框架提交Confirm/Cancel操作失败,不会导致不一致,因为服务最后都会超时而取消。

在实现TCC模式上,最重要的工作是设计一个稳定的、高可用的、扩展性强的TCC事务管理器。当然,设计并实现这样一个TCC事务管理器无疑是困难的,我们也不想重复去造轮子,幸好目前业界已经有一些相对比较成熟的实现方案可供参考。例如,tcc-transaction (github.com/changmingxi… TCC(github.com/iuyangming/… TCC)以及 Atomikos 公司自己的 TCC 方案(www.atomikos.om/Blog/TCCFor Transaction Management Across Microservices)。

tcc-transaction是TCC型事务的一种Java实现,官方提供的示例(github.com/changmingxi…