2PC与Sagas(分布式事务)

69

我正在探索分布式系统的见解,以及如何在涵盖多个服务、有界上下文和网络边界的业务交易中维护数据一致性。

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

  • 二阶段提交(2PC)
  • 事务补偿(Sagas)

2PC是一种协议,用于支持应用程序通过平台透明地利用全局ACID事务。它嵌入在平台中,据我所知,对于业务逻辑和应用程序代码来说是透明的。

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

那么,什么时候和为什么要使用Sagas而不是2PC,反之亦然?两者的用例和利弊如何?特别是,Sagas的脆弱性让我感到紧张,因为反转的分布式事务也可能失败。


有趣...没有答案,也没有关闭投票... - Saran
3个回答

85

在我看来(因为我认为它是有限制的,所以我不是2PC的重度用户):

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

随后的用例很明显:

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

示例:

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

我个人认为Saga能够做到2PC所能做的。相反则不准确。

我认为Sagas是通用的,而2PC涉及平台/供应商锁定。

更新/添加(可选读取):

我的答案已经在这里一段时间了,我看到这个主题已经引起了一些关注。

我想为那些来到这里并不确定要走哪条路的人澄清一些观点。

  1. Saga是领域建模(即技术无关)的概念,而2PC是一个技术特定的概念,一些(甚至很多)供应商实现了它。打个比方,这就像将领域事件(裸对象)与消息代理(例如RabbitMQ)进行比较。
  2. 如果你已经选择了实现此类协议的平台,那么2PC可能是一个不错的选择。但并非所有平台都这样做,因此我称其为一种限制。我认为人们找到了一个论据,即Saga更具限制性,因为它更难实现,但这就像说橙汁比苹果甜一样,两种不同的事物。
  3. 还要考虑人的因素。有些人(开发人员、架构师)是技术迷。他们称业务逻辑或领域模型为样板代码。我属于另一群人,认为领域模型是最有价值的代码部分。这种偏好也影响了Saga和2PC之间的决策,以及谁喜欢什么。我无法解释为什么应该优先考虑基于领域的思维方式而不是技术驱动的解决方案,因为它无法在此页面上展开,您可能需要通过我的文章在网上找到更多相关信息。
  4. @freakish在评论中提到了一个很好的观点:2PC更偏向于一致性,而Saga则会降级为“最终一致性”。如果您的情况中一致性比可用性更重要(请参阅CAP定理),那么也许您确实需要像2PC这样的系统事务协议。否则,我建议选择类似Saga的业务事务。请参阅《企业应用架构模式》(PEAA)中的“系统事务 vs 业务事务”。


3
回答不错,但是由于Saga能够完成2PC所能做的事情,因此它们需要实现重做机制,这会增加额外的开销。我对你回答中的最后一句话有些批评 :D - mehdi.loa
1
最后一行谈到了供应商锁定与保持通用性和平台独立性之间的关系。您觉得其中有什么不准确的地方? - Tengiz
1
很好的解释。 - Harvey Dent
1
@Tengiz 首先,你完全错了:一个事务需要一天、一周还是一年与一致性无关。长时间并不会使它最终一致。最终一致性意味着一旦系统开始改变其状态,它将在未来的某个时刻保持一致,但在此期间可能是不一致的。相对于强一致性,强一致性意味着状态始终保持一致,即使事务等待整整一年才提交。这只是意味着从外部看起来好像从未发生过,然后一年后它就神奇地出现了。 - freakish
2
2PC解决的问题实际上是由关系模型首先创建的。我曾经使用过不支持连接和事务的NoSQL数据库,并发现对于数据库事务的需求总是来自于领域表达能力和弹性的缺乏。每当我发现自己需要一个事务时,我就把它看作是我的领域模型中缺少了某些东西的红旗。2PC是一个糟糕的解决方案,隐藏了建模问题,但在某些情况下可能是可接受的捷径。@Tengiz提出了一个有效的观点,即这归结为是否将领域视为样板代码。 - tobiak777
显示剩余12条评论

5
我正在添加我的回答,以解决sagas和2PC之间的主要差异,即一致性模型。
另一方面,sagas是一系列本地事务,其中每个本地事务改变并持久化实体以及一些标志,指示全局事务的阶段并提交更改。
有趣的描述。这个标志到底是什么?每个节点是否应该在全局事务完成后提交更改(并由此跟踪)?每个节点将本地更改保持对外不可见,直到发生这种情况?如果是这样,那么它与2PC有何不同?如果不是这种情况,那么这个标志又是用来做什么的?
总的来说,据我所知,saga是一系列本地事务。如果序列中的任何节点失败,则流程将被反转,并且每个节点会按相反的顺序生成补偿事务。
然而,使用这个想法我们会遇到几个问题:第一个问题是你自己已经注意到的:如果补偿事务失败怎么办?如果在任何步骤上的任何通信失败怎么办?但还有更多,使用这种方法可以进行脏读取。例如,Node1成功了,而Node2失败了。然后我们在Node1上发出补偿事务。但是,如果另一个进程在Node1更新后但在补偿事务撤消该更新之前读取数据怎么办?潜在的不一致性(取决于您的要求)。
总的来说,sagas是:通过设计最终一致且高效(无全局资源锁定)。如果您对所有节点具有完全控制,则可以使saga变得强烈一致,但这需要大量手动(并且不明显,例如通信问题)的工作,并且可能需要一些资源锁定(因此我们将失去性能)。在这种情况下,为什么不一开始就使用2PC?
另一方面,2PC通过设计是强一致的,这使得它由于资源锁定而可能效率较低。
那么应该使用哪个?这取决于您的要求。如果需要强一致性,则使用2PC。如果不需要,则saga是一个有效的选择,可能更高效。
例如1。假设您创建了一个会计系统,用户可以在帐户之间转移资金。假设这些帐户位于单独的系统上。此外,您有一个严格的要求,即余额始终应为非负数(您不想处理隐含的债务),可能还有一个严格的要求,即最大金额可以设置且不能超过(考虑用于偿还债务的专用帐户:您不能放入比整个债务更多的钱)。那么saga可能不是您想要的,因为由于脏读取(和其他一致性现象),我们可能会得到超出允许范围的余额。2PC在这里将是一个更容易的选择。
例如2。同样,您拥有一个会计系统。但是这次允许超出范围的余额(谁拥有该系统将手动处理)。在这种情况下,也许saga更好。因为手动处理非常少量的问题状态可能比始终保持强一致性更便宜。

1
这个回答思路很好。我发表评论是因为我想澄清Saga如何实现始终为非负余额的示例。用户提交交易请求,这在某种程度上是一个Saga。Saga经历了几个阶段,第一阶段是扣除金额。第二阶段是添加金额。扣除金额本身就是一个原子操作,所以如果你成功扣除了,那么你就可以成功添加。唯一的问题是金额在某一时刻不存在(或者处于中间状态),但这并不是什么大问题。这种方法完全在Saga的能力范围之内。 - Tengiz
1
好的,为了完整起见。如果第二个系统失败了,你需要重试。Saga知道它已经扣除了金额,所以它需要重试。如果Saga的逻辑确定需要回滚事务,那也很简单,因为钱已经被取走了,你只需将其放回即可。账户始终保持正数。无论哪种方式,这个解决方案告诉我们Saga是一个业务概念。也就是说,你需要从头开始编写每个具体的Saga逻辑。这是有意设计的,不是什么坏事。 - Tengiz
@Tengiz 是的,一切都可以做到。但代价是什么?在我的简单场景中,这只是“添加”和“删除”操作的正确顺序问题,没错。然而,如果我将saga扩展到第三步(例如,将转移结果保存到第三个数据库),那么情况就不再如此了。我的观点是,现在我们进入了一个危险的领域,需要手动修复潜在的不一致性,并采用特定的方法。这并不容易。 - freakish
1
我从未说过saga是一个糟糕的设计。我只是在说它存在问题,使用它的人应该意识到这些问题。2PC也存在问题(主要是资源锁定)。 - freakish

3
你的比较不具备逻辑一致性。像Sagas这样的旧解决方案需要更多的工作来实现XA/2PC。
通常,2PC用于即时事务。通常,Sagas用于长时间运行的事务。
这是不正确的,如果您愿意,XA事务可以运行数周,无超时选项。我曾经使用过XA/2PC在系统中运行了一个星期,在某些情况下它们只运行了1毫秒。
我个人认为Saga能够做到2PC所能做的。相反则不准确。
不,Sagas是XA的一个更原始的解决方案。XA是更新的解决方案。在Sagas中,需要开发样板以处理事务。XA将事务管理的公共元素移动到底层平台,减少了开发人员必须管理的样板膨胀。
我认为Sagas是通用的,而2PC涉及平台/供应商锁定。
XA规范已被许多供应商实施,并且非常通用。在30年的时间里,跨多个组织的多个平台实施2PC从未成为问题。

请澄清最后一个问题。也许对于数据库来说是正确的,但我认为一般情况下不是这样的。例如,后端必须(1)请求第一个第三方支付提供商的API以增加余额,(2)请求第二个第三方支付提供商的API以减少余额,(3)将有关两个成功请求的记录保存到本地数据库中(以通过UI通知管理员)。那么如何使用2PC实现这种逻辑呢?我没有任何使用这项技术的经验。请描述具体的技术以及它如何处理这种情况。 - John
你应该能够下载XA规范的副本并查看其工作原理。数据库、消息服务器和应用程序容器,我已经使用了20多年,混合匹配来自许多供应商和开源项目的产品以及多种传输协议。但我认为你说得很对,你没有这项技术的经验。从Spring-not-Swing到微服务,有大量的意识形态、修辞、虚拟信号和负面营销,但是对于已经开发的技术和已经解决的问题,经验不是很丰富。 - Chris
@John,你会如何使用saga来实现呢?假设你的余额为0,你加上了10,saga继续执行,但最后一步失败了(无论什么原因)。你开始进行补偿交易。但是如果在此期间有人从现在有10的账户中提取了5怎么办?补偿交易到达时,你的余额现在是-5。这样可以吗?也许可以,也许不行,也许我的系统不允许负余额。这种情况可以通过2PC来保证。但是使用saga就不容易了。我的观点是:这些不是等价的,不应该以同样的方式处理。 - freakish
1
好的,我看到这里有一个完整的答案来反驳我的答案。尽管如此,我仍然坚持我的答案,因为我所看到的是一个技术爱好者试图在领域概念上推销一种技术。Saga是一个领域模型概念,而XA/2PC(我还不熟悉XA)听起来非常依赖于技术实现。这使得它在很多方面都不够灵活和不太受欢迎,包括我自己在内。 - Tengiz
抱歉,您的答案没有提到XA。我还没有看过您的答案。再来一次冒险。 - Tengiz
@freakish,我没有谈论比较saga和2PC的事情。我问的是XA/2PC或2PC如何处理上述情况。只是对技术很好奇。仅此而已 :) - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接