Saga 分布式事务解决方案与实践
转自 Saga分布式事务解决方案与实践:https://servicecomb.apache.org/cn/docs/distributed-transactions-saga-implementation/
传统的单体应用一般采用的是数据库提供的事务一致性,通过数据库提供的提交以及回滚机制来保证相关操作的ACID,这些操作要么同时成功,要么同时失败。各个服务看到数据库中的数据是一致的,同时数据库的操作也是相互隔离的,最后数据也是在数据库中持久存储的。这样的架构不具备横向扩展能力,服务之间的耦合程度也比较高,会存在单点故障。

在微服务架构中, 有一个database per service的模式, 这个模式就是每一个服务一个数据库。 这样可以保证微服务独立开发,独立演进,独立部署, 独立团队。
由于一个应用是由一组相互协作的微服务所组成,在分布式环境下由于各个服务访问的数据是相互分离的, 服务之间不能靠数据库来保证事务一致性。 这就需要在应用层面提供一个协调机制,来保证一组事务执行要么成功,要么失败。
两阶段提交其实比较简单,这边有两个资源提供准备和提交两个接口。
由于隔离性互斥的要求,在事务执行过程中,所有的资源都是被锁定的,这种情况只适合执行时间确定的短事务。 但是为了保证分布式事务的一致性,大都是采用串行化的隔离级别来保证事务一致性,这样会降低系统的吞吐。
但因为2PC的协议成本比较高,又有全局锁的问题,性能会比较差。 现在大家基本上不会采用这种强一致解决方案。
ACID与BASE

这里先简单介绍一下酸碱平衡中的酸 ACID。 原子性 事务作为整体来执行,要么全部执行,要么都不执行。一致性 事务应确保数据从一个一致的状态转变为另一个一致的状态。隔离性 多个事务并发执行时,一个事务的执行不应影响其他事务的执行。持久性 已提交的事务修改数据会被持久保持
酸碱平衡中的碱 BASE。 基本可用 可以保证分布式事务参与方不一定同时在线。柔性状态 允许系统状态更新有一定的延时,这个延时对客户来说不一定能察觉。最终一致性 通常是通过消息可达的方式保证系统的最终一致性。
这是分布式事务的一些基础理论数据库以及分布式的两阶段提交都提供了ACID的保证。 由于隔离性互斥的要求,在事务执行过程中,所有的资源都是被锁定的,这种情况只适合执行时间确定的短事务。后续大家开始通过业务逻辑将互斥锁操作从资源层面上移到业务层面,这并不是完全放弃了ACID,而是通过放宽一致性要求,借助本地事务来实现最终分布式事务一致性的同时也保证系统的吞吐。
TCC

TCC名字的由来是其中包含了 try, confirm, cancel三个操作。
与两阶段提交相比,TCC位于业务服务层, 没有单独的准备阶段,Try操作可以灵活选择业务资源锁的粒度。TCC是通过最终一致性来解决系统性能问题的这个设计,对我们设计抉择有很大的启发。 有些时候系统的技术问题是可以通过业务建模的方式来解决的。
领域建模
回顾之前的酸碱平衡的示例,我们得到的启发我们可以通过业务模型的改进提升系统性能。有关领域建模,这里给大家推荐两本书,一个是《领域驱动设计》,还有一个是《实现领域驱动设计》。
微服务设计目标高内聚低耦合,领域驱动设计能帮助构建一致的业务模型和系统实现模型,通过领域驱动设计可以明确微服务的界限上下文。通过在业务层面上把它们之间的强耦合关系拆开之后,带来最大的好处是,它们自身可以借助传统的数据库所提供的功能来实现一致性。只不过是在微服务与微服务之间,它们需要通过前面提到的这种柔性事务方式来做这件事情。
微服务事务一致性建议

微服务架构是一个在限定界限上下文内的松耦合的服务架构。微服务事务一致性的建议是什么呢?就是内刚外柔。在限定上下文内容借助数据库提供事务一致性来做强一致。在限定上下文之间依靠最终一致性方案来解决服务间协同问题。
对于柔性事务来常见的实现方式有TCC,和Saga,今天我们主要向大家介绍Saga的实现。
SAGA

Saga其实是30年前的一篇数据库论文里提到的一个概念。在论文中一个Saga事务就是一个长期运行的事务,这个事务是由多个本地事务所组成, 每个本地事务有相应的执行模块和补偿模块,当saga事务中的任意一个本地事务出错了, 可以通过调用相关事务对应的补偿方法恢复,达到事务的最终一致性。

Saga概念虽然提出来快30年了, 随着微服务的出现,越来越多的人想解决分布式事务问题,Saga也逐步受到大家的关注。
我们在实现Saga过程中,主要是参考了Caitie McCaffrey 在分布式Saga论文,以及Chris Richardson的研究。 大家可以通过下面的链接获取相关的信息。