分布式事务:Saga 事务模型
Saga 事务模型是一种异步、最终一致性的分布式事务解决方案,适用于业务流程长、参与者包含外部系统或遗留服务的场景。Saga 由一系列本地事务(sub-transaction)组成,每个事务都有对应的补偿操作,用于撤销事务结果。Saga 的执行顺序包括正常执行、回滚和重试,并支持向后恢复(回滚)和向前恢复(重试)两种策略。Saga 不保证 ACID 中的原子性和隔离性,但最终一致性得以实现。Sag
1. Saga 事务模型
Saga 模式是一种异步事务,最终一致性事务,Saga 协议的内容主要有两个部分:
- 每个 Saga 由一系列 sub-transaction Ti(sub-transaction 就是本地事务) 组成;
- 每个 Ti 都有对应的补偿动作 Ci,补偿动作用于撤销 Ti 造成的结果。
可以看到,和 TCC 事务模型相比,Saga 没有并没有预留资源,它的每一个 Ti 是本地事务,都是直接提交的。
Saga的执行顺序有三种:
- T1,T2,T3,… ,Tn
- T1,T2,… ,Tj,Cj,… ,C2, C1,其中_ 0 < j < n_
- T1,T2, … ,Tj(失败),Tj(重试),… , Tn
Saga定义了两种的恢复策略:
- Backward recovery:向后恢复,即上面提到的第二种执行顺序,其中 j 是发生错误的 sub-transaction,这种做法的效果是撤销掉之前所有成功的 sub-transation,使得整个 Saga 的执行结果撤销,实际就是回滚。
- Forward recovery:向前恢复,即上面提到的第三种执行顺序,适用于必须要成功的场景,其中j是发生错误的 sub-transaction。该情况下不需要 Ci。
Saga 事务模型对于 ACID 原则的保证:
A. 正常情况下保证;
C. 在某个时间点,会出现A库和B库的数据违反一致性要求的情况,但是最终是一致的;
I. Saga 事务会重叠执行,因此在某个时间点,A事务能够读到B事务部分提交的结果;
D. 和本地事务一样,只要 commit 则数据被持久;
因此 Saga 事务不提供 ACID 保证,因为原子性和隔离性不能得到满足。对于服务来说,实现Saga有以下这些要求:
- Ti 和 Ci 是幂等的。
- Ci 必须是能够成功的,如果无法成功则需要人工介入。
- Ti - Ci 和 Ci - Ti 的执行结果必须是一样的:sub-transaction 被撤销了。
第一点要求Ti和Ci是幂等的,举个例子,假设在执行Ti的时候超时了,此时我们是不知道执行结果的,如果采用 Forward recovery 策略就会再次发送 Ti,那么就有可能出现 Ti 被执行了两次,所以要求 Ti 幂等。如果采用 Backward recovery 策略就会发送 Ci,而如果 Ci 也超时了,就会尝试再次发送 Ci,那么就有可能出现 Ci 被执行两次,所以要求 Ci 幂等。
第二点要求 Ci 必须能够成功,这个很好理解,因为,如果 Ci 不能执行成功就意味着整个 Saga 无法完全撤销,这个是不允许的。但总会出现一些特殊情况比如 Ci 的代码有 bug、服务长时间崩溃等,这个时候就需要人工介入了。
第三点乍看起来比较奇怪,举例说明,还是考虑 Ti 执行超时的场景,我们采用了Backward recovery,发送一个 Ci,那么就会有三种情况:1. Ti 的请求丢失了,服务之前没有、之后也不会执行 Ti;2. Ti 在 Ci 之前执行;3. Ci 在 Ti 之前执行;对于第1种情况,容易处理。对于第2、3种情况,则要求 Ti 和 Ci 是可交换的(commutative),并且其最终结果都是 sub-transaction 被撤销。
2. Saga 的实现方式
Saga的实现有很多种方式,其中最流行的两种方式是:
- 事件驱动式:这种方式没有协调中心告诉 saga 参与服务该做什么,需要事先进行编排,每一个 saga 参与服务订阅彼此的事件并做出相应的响应,在 saga 事务执行期间,上游服务完成本地的 sub-transaction 之后,还需要发布具体的事件给下游参与者,下游参与者监听上游参与者的事件并决定是否需要针对监听到的事件做出响应,在响应的同时需要完成本地的 sub-transaction,并且发布事件给更下游的参与者。
- 命令驱动式:这种方式需要一个协调中心通过命令/回复的方式来和 Saga 事务参与服务进行交互,具体的操作就是按照业务的顺序,发送事务命令给 Saga 参与服务,并等待执行结果,每一个执行结果会触发下一个命令的发送,如果发生某个命令执行失败, 则会下发补偿操作命令进行事务撤销。
事件驱动式
事件驱动方式的实现方案可以采取可靠消息最终一致性方案来实现,这种方案的实现依赖一个可靠消息服务以及消息队列的高可用保障方案。
优点:
- 整个事务流程完全异步化,性能高,适合高并发场景;
- 松耦合,事务参与者监听事件并且彼此之间没有耦合。
缺点:
- 难以理解和维护:基于编排的 Saga 事务会导致业务过于松散,因为对于 Saga 事务的定义分散在各个参与者服务中,这就导致开发人员有时很难理解给定的 saga 事务的业务流程导致维护困难。
- 服务之间的循环依赖关系:saga 参与者订阅彼此的事件,这通常会创建循环依赖关系,可能会破坏架构设计的规范
命令驱动式
命令驱动式需要引入协调中心,协调中心一般采用有限状态机模式来实现,命令驱动式的优缺点如下
优点:
- 避免了业务方之间的环形依赖。
- 将分布式事务的管理交由协调中心管理,Saga 事务的定义集中在了协调中心,所以容易理解和维护。
- 减少了业务参与方的复杂度。这些业务参与方不再需要监听不同的消息,只是需要响应命令并回复消息。
- 测试更容易(分布式事务逻辑存在于协调中心,而不是分散在各业务方),回滚也更容易。
缺点:
- 引入了协调中心,使 Saga 事务开始依赖协调中心,可能会出现单点故障。
3. Saga 的优缺点
Saga 事务的适用场景:
- 业务流程长、业务流程多
- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口
优势:
- 一阶段提交本地事务,无锁,高性能
- 事件驱动架构,参与者可异步执行,高吞吐
- 补偿服务易于实现
缺点:
- 不保证隔离性(应对方案见后面文档)
更多推荐

所有评论(0)