掘金 后端 ( ) • 2024-05-06 23:07

基本概念

Saga事务是一种分布式事务实现方式,通过将大事务分解为一系列有序的、可以独立执行的本地事务来管理一致性。这些本地事务通过协调器或者事件驱动的方式依次执行,如果其中一个事务失败,则使用相应的补偿事务来撤销之前已经完成的事务,以确保系统的一致性,属于补偿性事务。

事务分类:

  • 本地事务: 在Saga中,本地事务是指在单个服务内部执行的事务,它只关心自己的数据一致性,并不需要考虑全局事务的状态。
  • 补偿事务: 如果在Saga执行过程中的任何点一个本地事务失败,之前已成功执行的事务将通过执行相应的补偿事务来进行回滚,撤销它们的效果。

实现方式

Saga事务有两种不同的实现方式,分别如下:

  • 命令协调(Order Orchestrator): 通过一个集中的协调器来管理所有事务操作的执行顺序和补偿流程。协调器根据事务执行的结果决定是继续下一个事务还是执行补偿事务。
  • 事件编排(Event Choreographyo): 每个服务独立监听其他服务发出的事件,并根据事件决定如何执行自己的本地事务或补偿事务。这种方式无需集中式协调器,但各服务必须自行定义处理逻辑。

命令协调

中央协调器(Orchestrator)以命令/回复的方式与每项服务进行通信,全权负责告诉每个参与者该做什么以及什么时候该做什么。整体流程如下图:

image.png

  1. 事务发起方的主业务逻辑请求中央协调器服务开启订单事务
  2. 中央协调器向库存服务请求扣减库存,库存服务回复处理结果。
  3. 中央协调器向订单服务请求创建订单,订单服务回复创建结果。
  4. 中央协调器向支付服务请求支付,支付服务回复处理结果。
  5. 主业务逻辑接收并处理中央协调器事务处理结果回复。

中央协调器必须事先知道执行整个事务所需的流程,如果有任何失败,它还负责通过向每个参与者发送命令来撤销之前的操作来协调分布式的回滚,基于中央协调器协调一切时,回滚要容易得多,因为协调器默认是执行正向流程,回滚时只要执行反向流程即可。

事件编排

命令协调方式基于中央协调器实现,所以有单点风险,但是事件编排方式没有中央协调器。事件编排的实现方式中,每个服务产生自己的时间并监听其他服务的事件来决定是否应采取行动。

在事件编排方法中,第一个服务执行一个事务,然后发布一个事件,该事件被一个或多个服务进行监听,这些服务再执行本地事务并发布(或不发布)新的事件。当最后一个服务执行本地事务并且不发布任何事件时,意味着分布式事务结束,或者它发布的事件没有被任何 Saga 参与者听到都意味着事务结束。

image.png

  1. 事务发起方的主业务逻辑发布开始订单事件。
  2. 库存服务监听开始订单事件,扣减库存,并发布库存已扣减事件。
  3. 订单服务监听库存已扣减事件,创建订单,并发布订单已创建事件。
  4. 支付服务监听订单已创建事件,进行支付,并发布订单已支付事件。
  5. 主业务逻辑监听订单已支付事件并处理。

如果事务涉及 2 至 4 个步骤,则非常合适使用事件编排方式,它是实现 Saga 模式的自然方式,它很简单,容易理解,不需要太多的代码来构建。

恢复策略

Saga事务执行过程中,操作失败,需要恢复数据,来保证一致性,有以下两种恢复策略:

  • 向后恢复(Backward Recovery): 撤销掉之前所有成功子事务。如果 任意本地子事务失败,则补偿已完成的事务。如异常情况的执行顺序 T1,T2,T3,..Ti,Ci,...C3,C2,C1。
  • 向前恢复(Forward Recovery): 即重试失败的事务,适用于必须要成 功的场景,该情况下不需要Ci。执行顺序:T1,T2,...,Tj(失败),Tj(重 试),...,Ti。

显然,向前恢复没有必要提供补偿事务,如果你的业务中,子事务(最终)总会成功,或补偿事务难以定义或不可能,向前恢复更符合你的需求。 理论上补偿事务永不失败,然而,在分布式世界中,服务器可能会宕机, 网络可能会失败,甚至数据中心也可能会停电。在这种情况下我们能做些 什么? 最后的手段是提供回退措施,比如人工干预。

优缺点

命令协调设计的优缺点:

① 优点:

  1. 服务之间关系简单,避免服务间循环依赖,因为 Saga 协调器会调用 Saga 参与者,但参与者不会调用协调器。
  2. 程序开发简单,只需要执行命令/回复(其实回复消息也是一种事件消息),降低参与者的复杂性。
  3. 易维护扩展,在添加新步骤时,事务复杂性保持线性,回滚更容易管理,更容易实施和测试。

② 缺点:

  1. 中央协调器处理逻辑容易变得庞大复杂,导致难以维护。
  2. 存在协调器单点故障风险。

事件编排设计的优缺点:

① 优点:

  1. 避免中央协调器单点故障风险。
  2. 当涉及的步骤较少服务开发简单,容易实现。

② 缺点:

  1. 服务之间存在循环依赖的风险。
  2. 当涉及的步骤较多,服务间关系混乱,难以追踪调测。

由于 Saga 模型没有 Prepare 阶段,因此事务间不能保证隔离性。当多个 Saga 事务操作同一资源时,就会产生更新丢失、脏数据读取等问题,这时需要在业务层控制并发,例如:在应用层面加锁,或者应用层面预先冻结资源。

Saga与TCC比较

Saga事务与TCC事务实现方式相比,少了预留资源的操作,导致补偿动作的实现比较麻烦:Ti 就是commit,比如一个业务是发送邮件,在TCC模式下,先保存草稿 (Try)再发送(Confirm),撤销的话直接删除草稿(Cancel)就行了。 而Saga则就直接发送邮件了(Ti),如果要撤销则得再发送一份邮件说明 撤销(Ci),实现起来有一些麻烦。

Saga和TCC都是补偿型事务,他们的区别为:

劣势:

  • 无法保证隔离性;

优势:

  • 一阶段提交本地事务,无锁,高性能;
  • 事件驱动模式,参与者可异步执行,高吞吐;
  • Saga 对业务侵入较小,只需要提供一个逆向操作的Cancel即可;而 TCC需要对业务进行全局性的流程改造;

总结

Saga事务是一种分布式事务模式,用于在微服务或分布式系统中保持数据一致性。它将全局事务分解为一系列独立的本地事务,每个本地事务在单个服务内完成业务逻辑并记录状态。如果其中任何一个本地事务失败,则通过执行补偿事务来撤销之前已成功的操作,以确保最终一致性。

Saga事务对于ACID的保证:

  1. 原子性(Atomicity):正常情况下保证。
  2. 一致性(Consistency):在某个时间点,会出现A库和B库的数据违反一致性要求的情况,但是最终是一致的。
  3. 隔离性(Isolation):在某个时间点,A事务能够读到B事务部分提交的结果。
  4. 持久性(Durability):和本地事务一样,只要commit则数据被持久。

Saga不提供ACID保证,因为无法保证原子性和隔离性。