下载本文的PDF版本 PDF

超越分布式事务的生命

一个叛教者的观点


Pat Helland

这是最初发表于 CIDR(创新数据库研究会议)2007 年的同名论文的更新和缩写版本。

事务是非常强大的机制,我几乎在我 40 年的职业生涯的大部分时间里都在研究它们。1982 年,我首次致力于在 Tandem NonStop 系统上提供事务。该系统的平均故障间隔时间以年4为单位衡量,并包括地理分布式两阶段提交,为强一致性事务提供出色的可用性。

包括 Google 的 Spanner2 在内的新创新,以极大的规模和出色的可用性提供了强一致性的事务环境。构建分布式事务以支持高可用性应用程序是一项巨大的挑战,它激发了卓越的创新和伟大的技术。不幸的是,这并未广泛提供给应用程序开发人员。

在大多数分布式事务系统中,单个节点的故障会导致事务提交停滞。这反过来会导致应用程序陷入僵局。在这样的系统中,系统越大,就越有可能宕机。当驾驶需要所有发动机都工作的飞机时,增加发动机会降低飞机的可用性。在数千个节点上运行分布式事务系统在没有特殊机制来容忍中断的情况下是不切实际的。当应用程序开发人员使用非高可用性分布式事务构建系统时,解决方案是脆弱的,必须被丢弃。自然选择开始发挥作用...

相反,应用程序是使用不提供事务保证但仍然满足其业务需求的技术构建的。

本文探讨并命名了在拒绝分布式事务的世界中,用于实现大规模关键任务应用程序的一些实用方法。主题包括对细粒度的应用程序数据进行管理,这些数据可能会随着应用程序的增长而随着时间推移重新分区。设计模式支持在这些可重新分区的数据片段之间发送消息。

这里的目标是减少人们在手工制作非常大型的可扩展应用程序时面临的挑战。此外,通过观察这些设计模式,行业或许可以努力创建平台,以便更容易开发可扩展的应用程序。最后,虽然本文的目标是可扩展的同构应用程序,但这些技术对于支持可扩展的异构应用程序(例如对移动设备的支持)也非常有用。

目标

本文重点介绍当应用程序开发人员只有本地数据库或事务系统可用时,如何构建成功的可扩展企业应用程序。本文不讨论可用性,仅讨论规模和正确性。

讨论可扩展应用程序

大多数可扩展应用程序的设计者都理解业务需求。问题在于事务和可扩展系统交互的问题、概念和抽象没有名称,也没有被清晰地理解。它们的应用不一致,有时会反噬设计者。本文的目标之一是发起一场讨论,以提高对这些概念的认识,从而形成一套通用的术语和一种商定的可扩展程序方法。

思考应用程序的近乎无限扩展

本文提出了一个关于近乎无限扩展影响的非正式思想实验。假设客户、可购买实体、订单、发货、医疗保健患者、纳税人、银行账户以及应用程序操作的所有其他业务概念的数量随着时间的推移而显着增长。通常,每个单独的事物不会变得更大;只是它们变得越来越多。CPU、DRAM、存储或其他一些资源是否首先饱和并不重要。在某个时候,需求的增加导致将以前在单台机器上运行的东西分布到更多机器上。这个思想实验让我们考虑成千上万台机器。

近乎无限的扩展是一种宽松、不精确且刻意模糊的方式,用于激发人们需要非常清楚地了解何时何地可以知道某些东西适合一台机器,以及如果无法确保它适合一台机器该怎么办。此外,您希望随着数据和计算负载几乎呈线性扩展。当然,以 N-log-N 的速度进行扩展,并具有较大的 log 值将会很棒。

描述可扩展应用程序的一些常见模式

近乎无限的扩展对业务逻辑有什么影响?我断言,扩展意味着在编写程序时使用一个名为实体的新抽象。一个实体一次只存在于一台机器上,并且应用程序一次只能操作一个实体。近乎无限扩展的一个结果是,这种编程抽象必须暴露给业务逻辑的开发人员。

通过命名和讨论这个尚未命名的概念,我们或许可以就一致的编程方法和对构建可扩展系统所涉及问题的统一理解达成一致。

此外,实体的使用对用于连接它们的消息传递模式具有影响。这导致了状态机的创建,该状态机应对消息传递不一致性,而这些不一致性被强加给试图构建可扩展业务问题解决方案的无辜应用程序开发人员。

一些假设

考虑以下三个假设,这些假设是断言的,而不是证明的。假设这些基于经验是正确的。

应用程序层和规模不可知性

让我们首先假设每个可扩展应用程序至少有两个层,如图 1 所示。这些层在对规模的感知上有所不同。它们可能还有其他差异,但这些与本次讨论无关。

Life Beyond Distributed Transactions

应用程序的较低层理解添加更多计算机是为了使系统扩展。除了其他工作之外,它还管理上层代码到物理机器及其位置的映射。较低层是规模感知的,因为它理解这种映射。我假设较低层向上层提供规模不可知的编程抽象。有许多规模不可知的编程抽象的示例,包括 MapReduce。3

使用这种规模不可知的编程抽象,应用程序的上层代码的编写无需担心扩展问题。通过坚持使用规模不可知的编程抽象,您可以编写应用程序代码,而无需担心在将其部署到不断增长的负载上时发生的变化。

随着时间的推移,这些应用程序的较低层可能会演变为新的平台或中间件,从而简化规模不可知 API 的创建。

事务范围

已经有很多关于在分布式系统上提供强一致性事务的概念的学术工作。这包括 2PC(两阶段提交)、1 Paxos5 和最近的 Raft。6 经典的 2PC 将在机器发生故障时阻塞,除非事务中的协调器和参与者本身具有容错能力,例如 Tandem NonStop 系统。Paxos 和 Raft 不会在节点故障时阻塞,但会像 Tandem 的系统一样进行额外的协调工作。

这些算法可以被描述为提供分布式系统上的强一致性事务。它们的目标是允许对分布在多台机器上的数据进行任意原子更新。更新存在于跨越多台机器的单个事务范围内。

不幸的是,在许多情况下,这对于应用程序开发人员来说不是一个选择。应用程序可能需要跨越信任边界、不同的平台以及不同的操作和部署区域。当您对分布式事务“说不”时会发生什么?

即使在本文首次撰写 10 年后的今天,真正的系统开发人员也很少尝试在超过几台计算机上实现强一致性事务。相反,他们假设多个独立的事务范围。每台计算机都是一个独立的范围,内部具有本地事务。

大多数应用程序使用至少一次消息传递

如果您是短寿命的 Unix 风格的进程,TCP/IP 非常棒,但请考虑应用程序开发人员面临的困境,他们的工作是处理消息并修改数据库中表示的一些持久数据。消息被消费但尚未确认。数据库已更新,然后消息被确认。在失败的情况下,这将重新启动并再次处理消息。

这种困境源于消息传递与持久数据的更新之间没有直接耦合,除非通过应用程序操作。虽然可以将消息的消费与持久数据的更新耦合起来,但这并不常用。这种耦合的缺失导致了故障窗口,在这些窗口中,消息被传递多次。消息管道与其丢失消息,不如至少传递一次消息。

这种行为的一个结果是,应用程序必须容忍消息重试和乱序传递。

需要证明的观点

撰写评论文章的好处在于您可以表达狂野的观点。以下是本文试图证明的几个观点。

可扩展应用程序使用唯一标识的实体

本文认为,每个应用程序的上层代码都必须操作一个名为实体的单个数据集合。对单个实体的大小没有限制,但它必须存在于单个事务范围(即一台机器)内。

每个实体都有一个唯一的标识符或键,如图 2 所示。实体键可以是任何形状、形式或风格。在某种程度上,它必须唯一地标识一个实体及其包含的数据。

Life Beyond Distributed Transactions

对实体的表示形式没有限制。它可以表示为 SQL 记录、XML、JSON、文件或任何其他内容。一种可能的表示形式是 SQL 记录的集合,可能跨越多个表,其主键以实体键作为其前缀。

实体表示不相交的数据集。每个数据都恰好驻留在一个实体中。

一个应用程序由许多实体组成。例如,订单处理应用程序封装了许多订单,每个订单都由唯一的订单 ID 标识。为了成为可扩展的订单处理应用程序,一个订单的数据必须与其他订单的数据不相交。

原子事务不能跨越实体

假设每台计算机都是一个单独的事务范围。本文稍后将提出论点,即原子事务不能跨越实体。程序员必须始终坚持每个事务中包含在单个实体内的数据。

从程序员的角度来看,唯一标识的实体就是事务范围。这个概念对为扩展而设计的应用程序的行为具有强大的影响。需要探讨的一个含义是,在为近乎无限的扩展进行设计时,备用索引不能保持事务一致性。

消息被寻址到实体

大多数消息传递系统不考虑数据的分区键,而是以无状态进程使用的队列为目标。标准做法是在消息中包含一些数据,告知无状态应用程序代码从何处获取所需的数据。这就是实体键。实体的数据由应用程序从某个数据库或其他持久存储中获取。

正在发生一些有趣的趋势。首先,实体集合的大小正在增长,超过一台计算机的容量。每个单独的实体通常都适合一台计算机,但它们的集合却不适合。无状态应用程序越来越多地根据某种分区方案路由以获取实体。

其次,获取和分区方案正在被分离到应用程序的较低层。这是有意地与负责业务逻辑的上层隔离的。

这种模式有效地通过使用实体键进行路由来定位实体。无状态 Unix 风格的进程和应用程序的较低层都只是为业务逻辑提供的规模不可知 API 的实现的一部分。上层规模不可知的业务逻辑只是将消息寻址到实体键,该实体键标识称为实体的持久状态。

实体管理每个合作伙伴的状态(活动)

规模不可知的消息传递实际上是实体到实体的消息传递。发送实体通过其持久状态显式表示,并通过其实体键标识。它向另一个实体发送消息,并通过其实体键标识该实体。接收实体由规模不可知的上层业务逻辑和表示其状态的持久数据组成。这通过其实体键标识。

回想一下消息至少传递一次的假设。接收实体可能会受到必须忽略的冗余消息的攻击。在实践中,消息分为两类:影响实体状态的消息和不影响实体状态的消息。不影响实体状态的消息很容易——它们是微不足道的幂等的。更改状态的消息需要更加小心。

为了确保幂等性(即,保证重试消息的处理是无害的),接收实体通常被设计为记住消息已被处理。一旦成功处理,重复的消息通常会生成与第一个消息的行为相匹配的另一个响应。

对接收到的消息的了解会创建状态,该状态按每个合作伙伴的基础进行包装。重要的观察结果是,状态是按每个合作伙伴的基础组织的,并且每个合作伙伴都是一个实体。

术语活动应用于管理双边关系每一侧的每个合作伙伴消息传递的状态。每个活动都恰好存在于一个实体中。一个实体将为每个合作伙伴实体拥有一个活动。

除了管理消息传递混乱之外,活动还用于管理松散耦合的协议。在原子事务不可能存在的世界中,试探性操作用于协商共享结果。这些操作在实体之间执行,并由活动管理。

构建工作流程以达成协议充满了挑战,这些挑战在其他地方有充分的记录。7 本文并非断言活动解决了这些挑战,而是它们为存储解决这些挑战所需的状态提供了基础。近乎无限的扩展导致了出人意料的细粒度工作流程风格的解决方案。参与者是实体,每个实体都使用关于所涉及的其他实体的特定知识来管理其工作流程。在实体内部维护的这种双边知识称为活动。

活动的示例有时是微妙的。订单应用程序向发货应用程序发送消息。它包括发货 ID 和发送订单 ID。消息类型可用于刺激发货应用程序中的状态更改,以记录指定的订单已准备好发货。通常,实施者在出现错误之前不会为重试而设计。很少,但偶尔,应用程序设计者会考虑并计划活动。

实体

本节更深入地研究实体的性质。

不相交的事务范围

每个实体都被定义为具有唯一键的数据集合,已知该集合存在于单个事务范围内。原子事务始终可以在单个实体内完成。

唯一键控实体

应用程序上层的代码自然是围绕具有唯一键的数据集合设计的。客户 ID、社会安全号码、产品 SKU 和其他唯一标识符可以在应用程序中看到。它们用作查找应用程序数据的键。事务原子性的保证仅在由唯一键标识的实体内才有效。

重新分区和实体

先前陈述的假设之一是,新兴的上层是规模不可知的,而下层决定了部署如何随着规模的变化而演变。随着部署的演变,特定实体的位置很可能会发生变化。应用程序的上层不能对实体的位置做出假设,因为那将不是规模不可知的。

如图 3 所示,实体使用哈希或键范围分区分布在事务范围之间。

Life Beyond Distributed Transactions

原子事务和实体

在可扩展系统中,您不能假设跨这些不同实体的更新事务。每个实体都有一个唯一的键,并且每个实体都容易放置到一个事务范围中。回想一下,近乎无限的扩展导致实体数量不可避免地增加,但单个实体的大小仍然足够小,可以容纳在一个事务范围(即一台计算机)中。

您如何知道两个单独的实体保证在同一事务范围内,因此可以原子更新?只有当单个唯一键统一了两者时,您才知道。现在它真的是一个实体了!

如果哈希用于按实体键进行分区,则无法知道两个具有不同键的实体何时落在同一个框中。如果键范围分区用于实体键,则大多数情况下,相邻的键值驻留在同一台机器上。有时您会很不走运,您的邻居会在另一台机器上。

一个简单的测试用例,它依赖于与键范围分区中的邻居的原子性,通常会成功。稍后,当重新部署将实体跨机器移动时,潜在的错误就会出现;更新不再是原子的。您永远不能指望不同的实体键值驻留在同一个位置。

更简单地说,应用程序的较低层将确保每个实体键(及其实体)都驻留在单台机器上。不同的实体可能位于任何位置。

规模不可知的编程抽象必须具有实体作为原子性边界的概念。理解实体、实体键的使用以及对跨实体缺乏原子性的明确承诺对于规模不可知的编程至关重要。

大型应用程序在当今行业中隐式地执行此操作;只是实体概念没有名称。从上层应用程序的角度来看,它必须假设实体是事务的范围。假设更多内容会在部署更改时中断。

考虑备用索引

我们习惯于使用多个键或索引来寻址数据。例如,有时客户通过社会安全号码引用,有时通过信用卡号引用,有时通过街道地址引用。假设极大的扩展量,这些索引不能驻留在同一台机器上或单个大型集群中。关于单个客户的数据不能被认为驻留在单个事务范围内。实体本身驻留在单个事务范围内。挑战在于,用于创建备用索引的信息副本必须被假定为驻留在不同的事务范围内。

考虑保证备用索引驻留在同一事务范围内。当近乎无限的扩展开始发挥作用时,实体集合被涂抹在大量的机器上。主索引和备用索引信息必须驻留在同一事务范围内。确保这一点的唯一方法是使用主索引定位备用索引。这会将您带到同一事务范围。如果您在没有主索引的情况下开始,并且必须搜索所有事务范围,则每个备用索引查找都必须检查几乎无限数量的范围,因为它会查找与备用键的匹配项。这最终将变得站不住脚。

唯一合乎逻辑的替代方案是执行两步查找。首先,查找备用键,这将产生实体键。其次,使用实体键访问实体。这非常类似于关系数据库内部,因为它使用两个步骤通过备用键访问记录。但是,近乎无限扩展的前提意味着两个索引(主索引和备用索引)不能被认为驻留在同一事务范围内。见图 4。

Life Beyond Distributed Transactions
规模不可知的应用程序程序无法原子地更新实体及其备用索引。上层规模不可知的应用程序必须设计为理解备用索引可能与使用其主索引(即实体键)访问的实体不同步。如图 4 所示,不同的键(主实体键与备用键)不能并置或原子更新。

过去作为备用索引自动管理的内容现在必须由应用程序手动管理。剩下的只有通过异步消息传递进行工作流程风格的更新。当您从备用索引读取数据时,您必须理解它可能与实体本身不同步。备用索引现在更难了。这是大型残酷系统的现实。

跨实体的消息传递

本节考虑使用消息连接独立实体。它检查命名、事务和消息、消息传递语义以及重新分区实体的影响。

跨实体通信的消息

如果您无法在同一事务中跨两个实体更新数据,则需要一种机制来在不同的事务中更新数据。实体之间的连接是通过消息进行的。

相对于发送事务是异步的

由于消息是跨实体的,因此与发送消息的决策相关联的数据在一个实体中,而消息的目标在另一个实体中。根据实体的定义,这些实体不能原子更新。消息不能在这些不同的实体之间原子发送和接收。

对于应用程序开发人员来说,在处理事务时发送消息,发送消息,然后事务中止,这将非常复杂。这意味着您没有导致某事发生的记忆,但它确实发生了。因此,对消息进行事务排队是必须的。见图 5。

Life Beyond Distributed Transactions

如果消息在发送事务提交之后才在目标位置可见,则该消息相对于发送事务是异步的。每个实体都通过事务前进到新状态。消息是从一个事务发出的刺激,并到达一个新实体,从而引起事务。

命名消息的目标

考虑应用程序的规模不可知部分的编程,因为一个实体想要向另一个实体发送消息。规模不可知的代码不知道目标实体的位置。实体键是已知的。

将实体键与实体的位置关联起来的任务落在了应用程序的规模感知部分。

重新分区和消息传递

当应用程序的规模不可知部分发送消息时,较低级别的规模感知部分会找到目标并至少传递一次消息。

随着系统扩展,实体会移动。这通常称为重新分区。实体的位置以及消息的目标可能会不断变化。有时消息会追逐到旧位置,结果却发现讨厌的实体已被发送到其他地方。现在消息将不得不跟随。

随着实体的移动,发送者和目标之间先进先出队列的清晰度偶尔会被破坏。消息被重复。后面的消息先于前面的消息到达。生活变得更加混乱。

由于这些原因,规模不可知的应用程序正在发展以支持对所有应用程序可见的消息传递进行幂等处理。这也意味着消息传递中的重新排序。

活动:应对混乱的消息

本节讨论应对消息重试和重新排序挑战的方法。它介绍了活动的概念,作为管理与合作伙伴实体关系所需的本地信息。

重试和幂等性

由于任何消息都可能被传递多次,因此应用程序需要一种规范来应对重复的消息。虽然可以构建低级别支持来消除重复消息,但在近乎无限的扩展环境中,低级别支持需要了解实体。当实体因重新分区而移动时,关于哪些消息已传递给实体的知识必须随实体一起移动。在实践中,这种知识的低级别管理很少发生;消息可能会被传递多次。

通常,应用程序的规模不可知(更高级别)部分必须实现机制,以确保传入消息是幂等的。这对于问题的性质来说不是必需的。重复消除当然可以构建到应用程序的规模感知部分中。但这尚未实现。因此,让我们考虑一下规模不可知应用程序的可怜的开发人员必须实现什么。

定义实质性行为的幂等性

如果消息处理的后续执行不会对实体执行实质性更改,则消息的处理是幂等的。这是一个模糊的定义,它将什么是实质性的以及什么不是实质性的规范留给应用程序。

如果消息不更改调用的实体而仅读取信息,则其处理是幂等的。即使写入了描述读取操作的日志记录,也是如此。日志记录对于实体的行为来说不是实质性的。什么是实质性的以及什么不是实质性的定义是特定于应用程序的。

自然幂等性

为了实现幂等性,至关重要的是消息不会引起实质性的副作用。有些消息无论何时处理都不会引发实质性的工作。这些消息是自然幂等的。

仅从实体读取某些数据的消息自然是幂等的。如果消息的处理确实更改了实体,但不是以实质性的方式更改实体呢?这些消息也将是自然幂等的。

现在变得更难了。某些消息暗示的工作实际上会导致实质性更改。这些消息不是自然幂等的。应用程序必须包含机制来确保这些消息也是幂等的。这意味着以某种方式记住消息已被处理,以便后续尝试不会进行实质性更改。

下一节考虑处理不是自然幂等的消息。

将消息作为状态记住

为了确保对非自然幂等的消息进行幂等处理,实体必须记住它们已被处理。这种知识是状态。状态随着消息的处理而累积。

此外,如果需要回复,则必须返回相同的回复。毕竟,您不知道原始发送者是否已收到回复。

管理每个合作伙伴的状态

为了跟踪关系和接收到的消息,规模不可知应用程序中的每个实体都必须以某种方式记住有关其合作伙伴的状态信息。它必须按每个合作伙伴的基础捕获此状态。让我们将此状态命名为活动。见图 6。如果实体与许多其他实体交互,则每个实体可能具有许多活动。活动跟踪与每个合作伙伴的交互。

Life Beyond Distributed Transactions

每个实体都由一组活动以及可能跨越活动的其他一些数据组成。

考虑处理包含许多要购买商品的订单。为每个单独商品的运输预留库存将是一项单独的活动。订单将有一个实体,仓库管理的每个商品将有单独的实体。不能假定这些实体之间存在事务。

在订单中,每个库存商品都将单独管理。消息传递协议必须单独管理。订单实体中包含的每个库存商品的数据是一项活动。虽然它没有这样命名,但这种模式经常存在于大型应用程序中。

在近乎无限扩展的应用程序中,您需要非常清楚地了解关系。您不能只进行查询来弄清楚什么是相关的。一切都必须使用双边关系的网正式地编织在一起。编织是通过实体键完成的。由于合作伙伴在远处,因此当合作伙伴到达时,您必须正式管理您对合作伙伴状态的理解,将其作为新知识。关于远处合作伙伴的本地信息称为活动。见图 7。

Life Beyond Distributed Transactions

通过活动确保最多接受一次

处理非自然幂等的消息需要确保每条消息最多处理一次(即,消息的实质性影响必须最多发生一次)。为此,必须记住消息的某些独特特征,以确保它不会被处理多次。

实体必须持久地记住从消息可以处理的状态到消息将不具有实质性影响的状态的转换。

通常,实体使用其活动来按每个合作伙伴的基础实现此状态管理。这至关重要,因为有时一个实体支持许多不同的合作伙伴,并且每个合作伙伴都将经历与该关系相关联的消息模式。每个合作伙伴的状态集合使这成为可能。

活动:在没有原子性的情况下应对

本节讨论了在没有分布式事务的情况下,规模非常大的系统如何做出决策。

管理分布式协议是一项艰苦的工作。在近乎无限扩展的环境中,不确定性的表示必须以细粒度的方式完成,该方式围绕每个合作伙伴关系定向。此数据在实体中使用活动的概念进行管理。

远距离的不确定性

分布式事务的缺失意味着在尝试跨不同实体做出决策时接受不确定性。跨分布式系统做出决策不可避免地会涉及在一段时间内接受不确定性。当可以使用分布式事务时,不确定性体现在对数据持有的锁中,并由事务管理器管理。

在不能依赖分布式事务的系统中,不确定性的管理必须在业务逻辑中实现。结果的不确定性保存在业务语义中,而不是在记录锁中。这只是工作流程。这不是魔法。您不能使用分布式事务,因此您使用工作流程。

导致实体和消息的假设现在导致结论,即规模不可知的应用程序必须使用工作流程自行管理不确定性。这是跨多个实体达成协议所必需的。

考虑一下企业之间常见的交互风格。企业之间的合同包括时间承诺、取消条款、预留资源等等。不确定性包含在业务功能的行为中。虽然比使用分布式事务更难实现,但这正是现实世界的运作方式...

同样,这只是对工作流程的论证。

活动和不确定性的管理

实体有时在与其他实体交互时会接受不确定性。这种不确定性必须按每个合作伙伴的基础进行管理,并且可以可视化为在合作伙伴的活动状态中被具体化。

很多时候,不确定性由关系表示。有必要按合作伙伴跟踪它。活动跟踪每个合作伙伴,因为它会进入新状态。

如果订购系统从仓库预留库存,则仓库会在不知道库存是否会被使用的情况下分配库存。这就是接受不确定性。稍后,仓库会 выяснить 预留的库存是否需要。这解决了不确定性。

仓库库存管理员必须为每个占用其商品的订单保留关系数据。当它连接商品和订单时,这些将按商品组织。每个商品都保留有关该商品未完成订单的信息。商品内的每个活动(每个订单一个)都管理订单的不确定性。

执行试探性业务操作

为了在实体之间达成协议,一个实体要求另一个实体接受不确定性。一个实体向另一个实体发送一个请求,该请求稍后可能会被取消。这称为试探性操作。在此步骤结束时,一个实体同意遵守另一个实体的意愿。

试探性操作、确认和取消

试探性操作的关键是取消权。如果请求实体决定不继续前进,则它会发出取消操作。如果它决定继续前进,则它会发出确认操作

当一个实体同意执行一项尝试性操作时,它同意让另一个实体决定结果。它接受不确定性,这增加了它的困惑。随着确认和取消的到来,不确定性降低,困惑也随之减少。随着旧问题的解决和新问题的出现,在生活中经历不断增加和减少的不确定性是正常的。

再次强调,这仅仅是工作流程,但它是以实体作为参与者的细粒度工作流程。

不确定性和近乎无限的扩展

不确定性的管理通常围绕双方协议展开。可能存在多个双方协议。这些协议像一个细粒度的双方协议网络一样编织在一起,使用实体键作为链接,并使用活动来跟踪远端合作伙伴的已知状态。

考虑一下房屋购买以及与产权托管公司(escrow company)的关系。买方与产权托管公司建立了信任协议,卖方、抵押贷款公司以及交易中涉及的所有其他方也是如此。

当您去签署购房文件时,您不知道交易的结果。您接受这一点,在产权托管结束之前,您是不确定的。唯一对决策具有控制权的一方是产权托管公司。

这是一个轮辐式的双边关系集合,用于在不使用分布式事务的情况下,让大量参与方达成一致。

在考虑近乎无限的扩展时,思考双边关系是很有趣的。通过从双边尝试/取消/确认(就像传统工作流程一样)构建,您可以看到实现分布式协议的基础。正如在产权托管公司(参见侧边栏)中一样,许多实体可以通过组合参与到一个协议中。

由于关系是双边的,因此将活动简单地概念化为“我记住的关于该合作伙伴的事情”就成为了管理庞大系统的基础——即使数据存储在实体中,而您不知道实体位于何处。您必须假设它在遥远的地方。尽管如此,它仍然可以用与规模无关的方式进行编程。

现实世界中近乎无限规模的应用非常希望拥有全局事务范围的奢侈。不幸的是,对于我们大多数人来说,在不引入系统故障时的脆弱性的情况下,这不容易实现。

相反,尝试性工作的不确定性管理被转移到与规模无关的应用程序的开发人员手中。它必须作为预留库存、信用额度分配和其他特定于应用程序的概念来处理。

结论

像往常一样,计算机行业正处于变革之中。

今天,新的设计压力正在强加给那些只想解决业务问题的程序员。他们的现实正在将他们带入一个近乎无限扩展的世界,并迫使他们进入与实际业务几乎无关的设计问题。今天如此,这篇文章在 2007 年首次发表时也是如此。

不幸的是,努力实现电子商务、供应链管理、金融和医疗保健应用等业务目标的程序员越来越需要考虑在没有分布式事务的情况下进行扩展。大多数开发人员根本无法访问提供可扩展分布式事务的强大系统。

我们正处于一个可以看清构建这些应用程序的模式的关口,但还没有人一致地应用这些模式。本文认为,这些新兴模式可以更一致地应用于为近乎无限的扩展而设计的手工应用程序开发中。

本文介绍并命名了在大型应用程序中涌现的几个形式化概念

• 实体是命名(键控)数据的集合,这些数据可以在实体内原子更新,但永远不能跨实体原子更新。

• 活动包括实体内部的状态集合,用于管理与单个合作伙伴实体的消息传递关系。

达成决策的工作流程在实体内的活动中运作。当观察近乎无限的扩展时,令人惊讶的是工作流程的细粒度性质。

许多应用程序在今天都在隐式地设计实体和活动。它们只是没有形式化,也没有一致地使用。在不一致使用的地方,会发现错误并最终修补。通过讨论和一致地使用这些模式,可以构建更好的大型应用程序,并且作为一个行业,我们可以更接近于构建允许业务逻辑程序员专注于业务问题而不是规模问题的解决方案。

参考文献

1. Bernstein, P. A., Hadzilacos, V., Goodman, N. 1987. 数据库系统中的并发控制和恢复。波士顿,马萨诸塞州:Addison-Wesley。

2. Corbett, J. C., et al. 2012. Spanner:谷歌的全球分布式数据库。第十届 USENIX 操作系统设计与实现研讨会 (OSDI)。

3. Dean, J., Ghemawat, S. 2004. MapReduce:大型集群上的简化数据处理。第六届操作系统设计与实现研讨会 (OSDI)。

4. Gray, J. 1990. 1985 年至 1990 年间 Tandem 系统可用性普查。IEEE 可靠性汇刊 39(4):409-418。

5. Lamport, L. 1998. 兼职议会。 计算机系统汇刊 16(2):133-169。

6. Ongaro, D., Ousterhout, J. 2014. 寻找一种易于理解的共识算法(扩展版本);https://raft.github.io/raft.pdf

7. Wachter, H., Reuter, A. 1992. ConTract 模型。在高级应用程序的数据库事务模型中:219-263。旧金山,加利福尼亚州:Morgan Kaufmann。

相关文章

与 Bruce Lindsay 的对话 为失败而设计可能是成功的关键 https://queue.org.cn/detail.cfm?id=1036486

公寓和云 环境中的约束为服务赋能。作者:Pat Helland https://queue.org.cn/detail.cfm?id=2398392

微软的协议文档计划:大规模互操作性测试 与 Nico Kicillof、Wolfgang Grieskamp 和 Bob Binder 的讨论 https://queue.org.cn/detail.cfm?id=1996412

Pat Helland 自 1978 年以来一直从事事务系统、数据库、应用程序平台、分布式系统、容错系统和消息传递系统的实施工作。为了消遣,他偶尔撰写技术论文。他目前在 Salesforce 工作。

版权 © 2016 由所有者/作者持有。出版权已授权给 。

acmqueue

最初发表于 Queue vol. 14, no. 5
数字图书馆 中评论这篇文章





更多相关文章

Marc Brooker, Ankush Desai - AWS 的系统正确性实践
构建可靠和安全的软件需要一系列方法来推理系统的正确性。除了行业标准的测试方法(如单元测试和集成测试)之外,AWS 还采用了模型检查、模糊测试、基于属性的测试、故障注入测试、确定性模拟、基于事件的模拟以及执行跟踪的运行时验证。形式化方法一直是开发过程的重要组成部分——也许最重要的是,形式化规范作为测试预言机,为 AWS 的许多测试实践提供了正确的答案。正确性测试和形式化方法仍然是 AWS 的关键投资领域,这些领域已经看到的投资回报加速了这一进程。


Achilles Benetopoulos - 数据中心计算机的中间表示
我们已经到了分布式计算无处不在的地步。内存应用程序数据大小正在超过单台机器的容量,因此有必要将其在集群上进行分区;在线服务具有高可用性要求,这只能通过将系统部署为多个冗余组件的集合来满足;高持久性要求只能通过数据复制来满足,有时甚至跨越广阔的地理距离。


David R. Morrison - 模拟:分布式系统中未被充分利用的工具
模拟在人工智能系统的出现中发挥着巨大的作用:我们需要一种高效、快速且经济高效的方式来训练人工智能代理在我们的基础设施中运行,而模拟绝对提供了这种能力。


Matt Fata, Philippe-Joseph Arida, Patrick Hahn, Betsy Beyer - 公司到云:谷歌的虚拟桌面
超过四分之一的 Googler 使用内部、数据中心托管的虚拟桌面。这种本地部署的产品位于公司网络中,允许用户从世界任何地方远程开发代码、访问内部资源和使用 GUI 工具。在其最显著的特性中,虚拟桌面实例可以根据手头的任务调整大小,具有持久的用户存储,并且可以在公司数据中心之间移动以跟随出差的 Googler。直到最近,我们的虚拟桌面都托管在使用名为 Ganeti 的自研开源虚拟集群管理系统的谷歌公司网络上的商用硬件上。今天,这项重要且对 Google 至关重要的工作负载在 GCP(Google Compute Platform)上运行。





© 保留所有权利。

© . All rights reserved.