两阶段提交和 Saga 模式的不同之处
1. 介绍
在当今的技术环境中,分布式系统因其优于单体系统而成为趋势。然而,软件架构中的一切都是一种权衡,这两种解决方案都不是防弹的。分布式系统面临的一个常见挑战是确保多个节点之间的数据一致性。
本教程中,我们将分析管理分布式事务的两种不同方法之间的差异:两阶段提交和 Saga 模式。
2. 分布式事务
事务是我们想要对数据执行的一组操作。通常,事务表现出全有或全无的行为:如果所有操作都成功,则事务被提交;如果任何操作失败,则事务将被回滚。在单体系统中,这种行为通常由数据库管理。
分布式事务还涉及一组跨多个服务的数据操作。这些事务比常规事务更复杂,因为它们需要确保每个服务与其他服务保持一致。这涉及协调多个独立服务的操作和状态,以保持整体数据的一致性。
作为一个例子,让我们考虑以下精心编排的场景。这是一个在线商店虚拟工作流的模拟:
在这个工作流程中,我们可以看到下订单会触发其他三个服务的更新:支付服务、库存服务和交付服务。我们使用订单服务作为编排器,它按顺序将请求发送到我们的三个域服务。因此,我们有一个分布式事务,因为我们正在更新三个不同的数据库。
3. 两阶段提交
两阶段提交(2PC)协议旨在确保分布式系统中的所有节点提交或回滚事务。因此,我们可以在分布式事务的上下文中实现跨多个数据库节点的原子性。
其中一个节点将充当协调器,也称为事务管理器,以启动 2PC。不出所料,它由两个阶段组成:准备阶段和提交阶段。
3.1. 准备阶段
在此阶段,事务协调器通过向所有参与节点发送准备好的请求来启动流程。每个参与者检查他们是否可以使用当前状态和资源完成交易。
之后,每个参与者都会对协调员进行投票。有两种可能的答案:
- 是:参与者承诺对交易进行承诺
- 否:参与者无法提交,需要中止交易
每位参与者都必须确保其决策的持久性。因此,需要使用像预写日志这样的模式来实现容错:
3.2. 提交阶段
在这里,协调员收集所有参与者的投票。如果所有参与者都投了赞成票,则协调器决定提交事务。如果任何参与者投了反对票,协调人决定中止交易。
根据其决定,协调器向所有参与者发送提交或中止请求。每个参与者执行所需的操作并释放任何获得的锁。之后,每个参与者都必须通知协调器它已经完成了提交或中止操作:
4. Saga 模式
Saga 模式是一种管理分布式事务的替代方法,尤其适用于涉及长期事务的微服务架构。
该模式不是通过单个、全有或全无事务来确保原子性,而是将事务分解为一系列更小、独立的子事务,也称为本地事务。每个子交易都由一个单独的服务管理,它们共同构成了一个 Saga。如果本地事务失败,saga 将执行一系列补偿事务,以撤消先前本地事务所做的更改。
在 saga 中,有三种不同类型的事务:
- 可补偿事务:可补偿事务是可以通过处理另一个具有相反效果的事务来撤销的事务。
- 透视事务:透视事务是 Saga 中的 go/no-go 点。 如果透视事务提交,则 Saga 将运行到完成为止。 透视事务可以是既不可补偿也不可重试的事务,也可以是 Saga 中的最后一个可补偿事务或第一个可重试事务。
- 可重试事务:可重试事务是透视事务之后且保证成功的事务。
有两种常见的 Saga 实现方法,即协调和编排。
3.1. 协调
在基于协调的方法中,每个本地事务都会发布触发其他服务中本地事务的事件。因此,不存在中央协调员告诉 SAGA 参与者该做什么。
工作流程示例:
- Order Placement Service 创建订单并发布事件
- Payment Service 接收事件,处理付款并发布确认事件
- Inventory Service 接收事件,更新库存并发布确认事件
- Delivery Service 接收事件,安排发货
如果其中任何一步失败,每个相关的服务都必需执行一个补偿性事务,以撤销其更改。
3.2. 编排
在基于编排的 SAGA 中,中央编排器(或协调器)管理整个事务。编排器向每个服务发送命令以执行其本地事务。它还通过发送命令来处理任何故障,以在必要时执行补偿事务。
工作流程示例:
- Order Placement Service 可被当作是编排器。一旦它创建了订单,就命令 Payment Service 去处理付款
- 处理完付款后,编排器安排 Inventory Service 去更新库存
- 最后,编排器让 Delivery Service 安排发货
如果其中的任何子事务失败了,编排器将发送命令撤销前一个操作。
5. 两阶段提交和 Saga 模式的不同之处
2PC 和 Saga 模式之间存在多个区别,做选择之前应该慎重考虑。
5.1. 原子性与最终一致性
两阶段提交通过在分布式事务之间保持原子性来确保强一致性。所有参与节点要么提交事务,要么回滚事务,从而在整个系统中实现一致的状态。
而 Saga 模式确保了最终的一致性,而不是强一致性。每个子事务都是独立提交的,如果发生故障,将执行补偿事务以恢复更改。这种方法可能会导致暂时的不一致。
5.2. 事务持续时间
2PC 协议最适合短期事务。这种方法要求在事务提交或中止之前持有锁,这可能会导致长时间运行的事务出现性能问题。
Saga 模式更适合长期事务,因为每个本地事务都是独立的。整个 SAGA 期间都不会持有锁,从而最大限度地减少了性能瓶颈。
5.3.复杂性
两阶段提交在逻辑方面更容易实现,因为它依赖于单个原子操作。然而,由于需要协调和故障时的阻塞风险,扩容和管理可能具有挑战性。
Saga 的实现更为复杂,因为它们需要定义补偿事务和管理部分故障。
5.4. 协调机制
在 2PC 中,我们有一个中央协调器来管理整个事务,使其成为单点故障。同时,如果是编排的话,saga 也可以非常类似地实现。此外,当我们实现 Saga 模式时,我们还有一种更非中心化的方法,即协调。
5.5. 可扩展性
通常,强一致性会影响可扩展性。因此,由于需要协调和跨分布式节点持有的潜在锁,2PC 的可扩展性较差。
另一方面,Saga 模式更具可扩展性,因为每个服务都独立管理其事务。
6. 小结
本文中看到的这两种方法都解决了管理分布式事务的问题。每种方法都有其优缺点,在选择一种方法之前应该慎重考虑。因此,选择可能依赖于系统的一致性、可扩展性和容错性的具体要求。