2PC vs Sagas(分布式事务)

2PC vs Sagas (distributed transactions)

我正在发展我对分布式系统的见解,以及如何在这些系统中保持数据一致性,其中业务事务涵盖多个服务、有界上下文和网络边界。

这里有两种我知道的用于实现分布式事务的方法:

2PC 是应用程序在平台支持下透明地使用全局 ACID 事务的协议。嵌入到平台中,据我所知对业务逻辑和应用程序代码是透明的。

另一方面,Sagas 是一系列本地事务,其中每个本地事务都会改变并持久化实体以及一些指示全局事务阶段的标志并提交更改。换句话说,事务状态是域模型的一部分。回滚是提交一系列 "inverted" 事务的问题。在任何一种情况下,服务发出的事件都会触发这些本地事务。

现在,什么时候以及为什么会在 2PC 上使用 sagas,反之亦然?两者的用例和 pros/cons 是什么?特别是sagas的脆弱性让我很紧张,反向分布式事务也可能失败。

据我了解(不是 2PC 的大用户,因为我认为它有限制):

  • 通常,2PC 用于立即 交易。
  • 通常,Sagas 用于 长 运行 笔交易。

之后用例很明显:

  • 2PC 允许您在一个请求中提交整个事务,跨系统和网络跨越该请求。假设每个参与的系统和网络都遵循该协议,您可以无缝地提交或回滚整个事务。
  • Saga 允许您将交易分成多个步骤,跨越很长一段时间(不一定是系统和网络)。

示例:

  • 2PC:为每个收到的发票请求保存客户,同时由 2 个不同的系统管理。
  • Sagas:预订由多个联程航班组成的航班行程,而每个单独的航班由不同的航空公司运营。

我个人认为 Saga 可以做 2PC 可以做的事情。相反的不准确。

我认为 Sagas 是通用的,而 2PC 涉及 platform/vendor 锁定。

Updates/Additions(选读):

我的回答已经放在这里有一段时间了,我看到这个话题从那以后获得了一些关注。

我想就这个话题向那些来到这里但不确定该走哪条路的人澄清几点。

  1. Saga 是一个领域建模(即与技术无关)的概念,而 2PC 是一个特定于技术的概念,一些(可能很多)供应商正在实施它。打个比方,如果我们将领域事件(裸对象)与消息代理(例如 RabbitMQ)进行比较,也是一样的。
  2. 如果你无论如何都嫁给了实现这种协议的平台,2PC 可能是一个不错的选择。并非所有人都这样做,因此我称之为限制。我看到人们发现了一个论点,即 Saga 更受限制,因为它更难实现,但这就像说橙子多汁而不是苹果甜。两个不同的东西。
  3. 还要考虑人为因素。有些人(开发人员、架构师)是技术极客。他们将业务逻辑或领域模型称为样板代码。我属于另一群人,他们认为领域模型是最有价值的代码片段。这种偏好也会影响 Saga 和 2PC 之间的决策,以及谁喜欢什么。我无法解释为什么您应该更喜欢领域驱动的思考而不是技术驱动的解决方案,因为它不适合此页面,您将放弃阅读我的答案。请在网上找到更多信息,也许是通过我的著作。

@freakish 在评论中提到了一个公平的观点:2PC 更喜欢一致性,而 Saga 将其降级为“最终一致性”。如果您遇到一致性比可用性更重要的情况(请阅读 CAP), then maybe you do need a system transaction protocol like 2PC. Otherwise, I recommend going with business transactions such as Saga. Please read System Transactions vs Business Transactions e.g. in PEAA.

您的比较在逻辑上不一致。像 Sagas 这样的旧解决方案需要更多的工作来实现 XA/2PC

Typically, 2PC is for immediate transactions. Typically, Sagas are for long running transactions.

这是不正确的,如果您愿意,XA 事务可以 运行 数周,无超时是一种选择。我在 XA/2PC 运行 的系统上工作了一个星期,有些系统 运行 持续了 1 毫秒。

I personally consider Saga capable of doing what 2PC can do. Opposite is not accurate.

不,Sagas 是 XA 的更原始的解决方案。 XA 是较新的解决方案。在 Sagas 中,需要开发样板来处理交易。 XA 将事务管理的通用元素移至底层平台,减少了开发人员必须管理的样板膨胀。

I think Sagas are universal, while 2PC involves platform/vendor lockdown.

XA 规范已被许多供应商实施,并且非常通用。 30 多年来,跨多个组织的多个平台实施 2PC 一直不是问题。

我添加我的答案是为了解决 sagas 和 2PC 之间的主要区别,后者是一种一致性模型。

Sagas, on the other hand, are series of local transactions, where each local transaction mutates and persist the entities along with some flag indicating the phase of the global transaction and commits the change.

有趣的描述。这面旗帜到底是什么?每个节点是否应该在全局事务完成后提交更改(并且由该标志跟踪)?在这种情况发生之前,每个节点都对外部不可见本地更改?如果是这样,那么它与 2PC 有何不同?如果不是这样,那么这个标志是干什么用的?

一般来说,据我了解,saga 是一系列本地事务。如果序列中的任何节点发生故障,则流程将反转,每个节点都会以相反的顺序生成补偿交易。

然而,有了这个想法,我们遇到了几个问题:第一个是您自己已经注意到的:如果补偿交易失败怎么办?如果任何一步的任何通信失败怎么办?但还有更多,使用这种方法脏读是可能的。假设 Node1 成功,Node2 失败。然后我们在 Node1 上发出一个补偿交易。但是,如果另一个进程在 Node1 更新之后但在补偿事务恢复该更新之前读取数据怎么办?潜在的不一致(取决于您的要求)。

一般来说,sagas 是:最终一致且高效(无全局资源锁定)的设计。如果您可以完全控制所有节点,那么可以使 saga 高度一致,但这需要大量手动(并且不明显,例如通信问题)工作,并且可能需要一些资源锁定(因此我们将失去性能)。既然如此,为什么不首先使用 2PC?

另一方面,2PC 在设计上是高度一致的,这可能会由于资源锁定而降低效率。

那么使用哪一个呢?这取决于您的要求。如果您需要强一致性,那么 2PC。如果不是,那么 saga 是一个有效的选择,可能更有效。

示例 1. 假设您创建了一个会计系统,用户可以在其中进行账户间转账。假设这些帐户位于不同的系统上。此外,您严格要求余额应始终为非负数(您不想处理隐性债务),并且可能严格要求可以设置且不能超过最大金额(考虑用于偿还债务的专用账户:你不能投入比全部债务更多的钱)。那么 sagas 可能不是你想要的,因为由于脏读(和其他一致性现象),我们可能会以超出允许范围的平衡结束。 2PC 将是一个更容易的选择。

示例 2. 同样,您有一个会计系统。但是这次允许超出范围的平衡(谁拥有系统将手动处理)。在那种情况下,也许 sagas 更好。因为手动处理极少数麻烦的状态可能比始终保持强一致性更便宜。