65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Azure 上使用 Saga 模式实现分布式事务

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.44/5 (4投票s)

2023年12月21日

CPOL

8分钟阅读

viewsIcon

7886

downloadIcon

80

如何在 Azure 上实现分布式事务?

引言

随着云平台的日益普及,微服务正变得越来越普遍。现在可以快速实施最佳架构实践并轻松实例化多个数据存储。使用领域驱动设计(DDD)的术语,这促进了具有自身代码和存储的独立有界上下文的实现。因此,这种范式简化了部署并缩短了交付时间。这些好处现在已得到广泛认可。

另一方面,微服务也带来了自身的挑战。由于数据现在分布在多个存储库中,而不是集中在一个数据存储中,因此我们无法再依赖 SQL 机制来保证完整性和一致性,正如开发人员多年来一直做的那样。简单来说,Oracle 或 Microsoft 以前提供的事务机制使我们能够自信地确信我们的数据始终处于一致状态。然而,在分布式系统中,保持数据一致性已成为日常关注的问题。

在本系列文章中,我们的目标是通过在 Azure 平台上实施 Saga 模式的变体来解决这些挑战。

免责声明

我们提供的定义并非官方定义,我们提出的实现也应接受审查。主要目标是说明问题并展示解决这些问题的潜在方法。

本文最初发布于 此处。请参考它以获得全面的概述。

什么是事务?

关系数据库中的事务是一个基本概念,在突出这些技术的能力方面起着关键作用。开发人员一直以来都隐式地信任 Oracle 或 SQL Server 实现的内部机制来保证数据完整性和一致性。

CREATE TABLE ValueTable (id INT);
BEGIN TRANSACTION;
  INSERT INTO ValueTable VALUES(1);
  INSERT INTO ValueTable VALUES(2);
COMMIT;

在提供的示例中,创建了一个表,并尝试了两次插入。

  • 如果其中一次插入失败,表中将不存在任何行。
  • 相反,如果两次插入都成功,则表中将存在两行。

此功能被广泛接受,以至于这种看似简单的操作背后的复杂性常常被忽视。

只要传统的架构主要是单体的,具有单一的代码库和统一的 SQL 存储库,这也不是一个重大问题。许多成功的应用程序的实现都没有关注这些问题。然而,随着微服务范式的出现,一些以前被忽视的挑战重新出现,现在必须加以解决。

事实上,考虑一个为微服务架构设计的现代电子商务平台,如图所示,它划分了有界上下文。当客户下单时会发生什么?

在这种情况下,由于涉及两个不同的数据存储,因此无法诉诸传统事务。最简单的处理方法是完全省略事务机制。

大多数时候,它会按预期工作(考虑到网络问题相对不常见)。下订单时,它应该会出现在两个数据存储中。但是,请考虑在插入 Order 数据库后不久出现问题的场景。

在这种情况下,问题可能非常严重:在 Order 数据库中插入了一个记录,并且商家将其包含在他们的会计中。然而,客户永远不会收到他们的订单,导致可能发生的任何后果。

为什么现在会出现这个问题?

实际上,这个问题从未消失;相反,它被现有数据库的复杂机制所掩盖。随着分布式架构和所涉及的众多技术的兴起,它不再可以委派,而是成为开发人员面临的挑战。

谁说微服务是一个更简单的解决方案?像所有工程范式一样,它简化了某些方面,但也带来了其他非常尖锐的后果。事务就是其中的副产品。

注意

它比这更复杂。随着 NoSQL 数据库(如面向文档的数据库)的出现,在一个数据存储内跨事务并不总是可行的。例如,CosmosDB 仅允许在同一容器内进行事务(而不是跨容器),并施加了严格的限制。

在本系列的后续部分,我们将介绍解决此问题的方法。传统上,这些挑战及其解决方案被称为模式,此处也不例外。Saga 模式由此而来。

什么是 Saga 模式?

Saga 模式是一种用于分布式系统以管理长期事务的设计模式。它将一个事务分解为一系列更小、独立的步骤或活动,每个步骤都有自己的补偿事务。这种方法能够在分布式环境中实现更好的弹性和容错能力。

  • 如果一个步骤失败,则会执行前面步骤的补偿事务以撤销更改并保持一致性。
  • Saga 中的每个步骤代表一个单独的原子事务,整个步骤序列确保了整个事务的完整性。

这个定义有些抽象,可能看起来有点难以捉摸,但它在具体方面到底意味着什么?

Saga 模式在具体方面是什么?

我们将通过示例来剖析定义中的每个术语。

Saga 模式用于分布式系统

这是定义中简单明了的部分。Saga 模式主要用于需要互连和协作的多个独立服务的系统。在传统的单体应用程序中,通常只有一个真相来源和现有的事务机制,Saga 模式的相关性较低。

Saga 模式在微服务架构中尤其有价值,在这些架构中,由于系统的分布式和去中心化性质,传统的 ACID 事务可能难以实现。它提供了一种更灵活、可扩展的方式来管理此类环境中的复杂、多步事务。

它将事务分解为一系列更小的步骤

Saga 模式依赖于本地事务,而不是执行可能影响性能的跨多个系统的庞大事务。每个子系统,例如订单微服务或交付模块,都负责启动自己的连贯机制。这种方法本身就很合乎逻辑:每个模块都对自身技术的复杂性有着深刻的理解,因此最适合确定如何在其环境中执行事务。

但是,如果 Saga 模式仅仅是每个子系统方便地执行的或多或少独立的本地事务序列,那么它将缺乏效率和价值。这就是引入补偿机制的原因。

每个步骤都有自己的补偿事务

补偿事务模式涉及为 Saga 中的每个步骤或活动定义和实现**补偿**事务,并在发生全局故障或错误时用于撤销相应原始事务的影响。当序列中的一个步骤遇到问题时,将触发每个先前步骤的补偿事务。这些补偿事务经过精心设计,旨在撤销或补偿其相应成功执行的步骤期间所做的更改。

总结

补偿事务模式确保在发生故障时,可以通过系统地应用补偿事务将系统恢复到一致状态。这种方法提供了一种在分布式环境中尽管发生故障也能保持数据完整性和一致性的方法。

谁负责监督整个过程的执行?

该机制需要一个中央协调器,通常称为编排器,它指示其他服务执行其本地事务,并在必要时在发生故障时回滚它们。在无服务器架构(如 Azure)的上下文中,此编排器可以实现为 Azure Function。

Azure Function 作为执行器,执行第一个本地事务,如果第一个成功,则执行第二个。如果发生故障,执行器将使用先前实现的补偿逻辑回滚第一个事务。

信息 1

为了提供全面的视角,需要注意的是,Saga 模式不仅可以通过编排器实现,还可以通过一种称为**编舞**的机制实现。在这种方法中,每个本地事务在成功时都会发布一个事件,其他事务会订阅这些事件,并在满足其条件时执行。但是,本系列不会涵盖此过程。

信息 2

这种方法更容易理解和监督,因为 Saga 执行逻辑是集中的。但是,如果设计不当,它也可能构成潜在的瓶颈和单点故障。

给我一个例子

我们继续之前的场景,再次设想一个订单已在 Order 数据库中成功下达,但出现错误阻碍了发货记录。下图说明了如何使用 Saga 模式处理这种情况。

如果补偿逻辑失败怎么办?

有时补偿逻辑可能会失败。这种情况可以通过以下方法的组合来解决:

  • 对补偿操作实现重试模式
  • 利用异常处理

如果自动流程无法解决问题,则备选方案是生成异常报告,以便进行手动审查。这种手动审查允许根据已识别的问题采取适当的措施。

重要

诉诸手动流程可能显得繁琐,但在这个世界上,没有什么东西是没有代价的。我们将微服务(如模块化和易于部署)的优势,与很少且偶尔需要诉诸手动方法的场合进行权衡。

但让我们把理论放在一边。现在是时候关注实际实现了,在 Azure 和 C# 上使用无服务器架构演示 Saga 模式。请访问 此链接 观看实际操作。或者,您可以下载随附的源代码。

历史

  • 2023 年 12 月 21 日:初始版本
© . All rights reserved.