译|Eventually Consistent

简介: 译|Eventually Consistent

一年前,我写过一致性模型的文章的第一个版本。因为当时写的很匆忙,而且这个主题非常重要,值得更缜密的对待,所以我并不是很满意。ACM Queue 为将其发布到自己觉得杂志上,所以请我仔细推敲。我得以借此机会改进这篇文章。本文就是最新的版本。

最终一致性 - 在全球范围内构建可靠的分布式系统需要在一致性和可用性之间进行权衡。

亚马逊云计算的基础是诸如 S3(Simple Storage Service)、SimpleDB、EC2(Elastic Compute Cloud)等基础设施,为构建互联网规模级别计算平台和种类繁多的应用提供了资源。这些基础设施服务的要求非常严格,需要在安全性、可扩展性、可用性、性能和成本效益方面获得高分,与此同时还要持续为全球数以百万计的客户提供服务。

在这些服务幕后,是全球范围内运行的大规模分布式系统。这种规模带来了额外的挑战。因为当系统处理数以万亿计的请求时,通常情况下发生概率较低的的事件会必然发生,需要在系统设计和架构中预先考虑。鉴于这些系统遍及全球范围,我们通常使用复制技术来保证一致性的性能和高可用性。尽管复制使我们更接近目标,却不能以完全透明的方式实现这些目标。在许多情况下,这些服务的客户将面临服务内部使用复制技术的后果。

其中一种表现方式是提供的数据一致性的类型,特别是底层分布式系统为数据复制提供最终一致性模型时。在亚马逊设计这些大规模系统时,使用了一套与大规模数据复制相关的指导原则和抽象方法,并专注于高可用性和数据一致性之间的平衡。在本文中,我介绍了一些相关的背景知识,包含了我们交付需要在全球范围内运行的可靠分布式系统的方法。本文的早期版本于 2007 年 12 月在 All Things Distributed 博客上发表,在读者的帮助下得到了极大的改进。

历史视角

在理想世界里,只有一种一致性模型:当更新发生时,所有观察者都能看到那个更新。该模型第一次出现难以实现的情况是在70年代末的数据库系统中。关于该主题最好的“时期作品”是 Bruce Lindsay 等人的”分布式数据库笔记”。 它阐述了数据库复制的基础性原则,并讨论了许多处理实现一致性的技术。其中许多技术都试图实现分发透明性——即对系统用户来说,似乎只有一个系统而不是多个协作系统。在此期间,许多系统采取的做法是倾向于让整个系统失败,而非破坏其透明度。

在90年代中期,随着大型互联网系统的兴起,这些做法被重新审视。当时的人们开始考虑可用性可能是这些系统最重要的属性的想法,但他们正在为拿什么权衡而苦苦挣扎。加州大学伯克利分校系统教授、当时的 Inktomi 负责人 Eric Brewer 在 2000 年 PODC(分布式计算原理)会议上的主题演讲中将不同的权衡结合在一起。他提出了 CAP 定理,该定理指出共享数据系统的三个属性——数据一致性、系统可用性和对网络分区的容忍度——在任何给定时间只能实现两个。更正式的认定可以在 Seth Gilbert 和 Nancy Lynch 2002 年的一篇论文中找到。

一个不容忍网络分区的系统可以实现数据的一致性和可用性,通常通过使用事务协议来实现。要实现这一点,客户端和存储系统必须是同一环境的一部分;在某些情况下,它们作为一个整体失败,因此,客户端无法观察到分区。一个重要的观察结果是,在较大的分布式系统中,网络分区是给定的;因此,一致性和可用性无法同时实现。这意味着对于要删除的内容有两种选择:放宽一致性将允许系统在可分区条件下保持高可用性,而将一致性作为优先级意味着在某些条件下系统将不可用。

两种选项都要求客户端开发者了解系统提供的内容。如果系统强调一致性,开发者需要处理系统可能不可用的事实,例如:写入。如果因为系统不可用写操作失败,那么开发者不得不处理如何处置要写入的数据。如果系统强调可用性,那么总能接受写操作,但是在某些情况下,读操作不会反映最近完成的写入的结果。然后,开发人员必须决定客户端是否需要始终访问绝对最新的更新。大量的应用程序可以处理稍微陈旧的数据,并且在此模型下可以很好地提供服务。

原则上,ACID 属性(原子性、一致性、隔离性、持久性)中定义的事务系统的一致性属性是一种不同的一致性保证。在 ACID 中,一致性是指当事务完成时,数据库处于一致状态的保证;例如,当从一个账户向另一个账户转账时,两个账户中持有的总金额不应改变。在基于 ACID 的系统中,这种一致性通常是编写事务的开发人员的责任,但可以由数据库管理完整性约束来辅助。

一致性 —— 客户端和服务器

有两种看待一致性的方法。一种是从开发人员/客户的角度来看:他们如何观察数据更新。第二种方式来自服务器端:更新如何流经系统以及系统可以为更新提供什么保证。

客户端一致性

客户端具有以下组件:

  • 一个存储系统。 目前我们将其视为一个黑匣子,但人们应该假设在它幕后是大规模和高度分布式的,并且构建它是为了保证持久性和可用性。
  • 进程A。 这是一个对存储系统进行写入和读取的进程。
  • 进程B和C。 这两个进程独立于进程A,对存储系统进行读写操作。它们是真正的进程还是同一进程中的线程无关紧要;重要的是它们是独立的,共享信息需要通信。

客户端一致性与观察者(在本例中为进程 A、B 或 C)如何以及何时查看对存储系统中的数据对象所做的更新有关。在以下说明不同类型一致性的示例中,进程 A 对数据对象进行了更新:

  • 强一致性(Strong consistency)。 更新完成后,任何后续访问(通过 A、B 或 C)都将返回更新后的值。
  • 弱一致性(Weak consistency)。 系统不保证后续访问将返回更新后的值。在返回值之前需要满足许多条件。更新和保证任何观察者总是看到更新值之间的时间段被称为不一致窗口。
  • 最终一致性(Eventual consistency)。 弱一致性的一种特殊形式;存储系统保证如果没有对对象进行新的更新,最终所有访问都将返回最后更新的值。如果没有发生故障,则可以根据通信延迟、系统负载以及复制方案中涉及的副本数量等因素确定不一致窗口的最大大小。最流行的实现最终一致性的系统是 DNS(域名系统)。名称的更新根据配置的模式并结合时间控制的缓存进行分发;最终,所有客户端都会看到更新。

最终一致性模型有许多需要考虑的重要变种:

  • 因果一致性(Causal consistency)。 如果进程 A 通知进程 B 已更新数据项,则进程 B 的后续访问将返回更新后的值,并且保证写入会取代较早的写入。与进程 A 没有因果关系的进程 C 的访问遵循正常的最终一致性规则。
  • 读写一致性(Read-your-writes consistency)。 这是一种重要的模型,其中进程 A 在更新数据项后,始终访问更新的值并且永远不会看到旧值。这是因果一致性模型的一个特例。
  • 会话一致性(Session consistency). 这是前一模型的实用版本,其中进程在会话上下文中访问存储系统。只要会话存在,系统就保证读写一致性。如果会话由于某种故障场景而终止,则需要创建新会话,并且保证会话之间不会重叠。
  • 单调读一致性(Monotonic read consistency). 如果进程看到了对象的特定值,则任何后续访问都将永远不会返回任何先前的值。
  • 单调写一致性(Monotonic write consistency). 在这种情况下,系统保证通过同一进程串行化写入。不保证这种一致性级别的系统是出了名的难以编程。

上述特性可以组合。例如,可以将单调读与会话一致性相结合。 从实践的角度来看,这两个特性(单调读取和读取你的写入)在最终一致性系统中是最可取的,但并非总是必需的。开发者使用这两个特性可以更加简单的构建应用程序,同时允许存储系统放宽一致性并提供高可用性。

正如您从这些变种中看到的那样,可能存在多种不同的情况。是否可以处理后果取决于特定的应用程序。

最终一致性并不是极致分布式系统的某些深奥特性。许多提供主备可靠性的现代 RDBMS(关系数据库管理系统)以同步和异步模式实现复制技术。在同步模式下,副本更新是事务的一部分。在异步模式下,更新延迟到达备份,通常是通过日志传送。在后一种模式下,如果主服务器在日志发送之前发生故障,从提升为主的副本中读取,将出现旧的、不一致的值。同样为了支持更好的可扩展读取性能,RDBMS 已经开始提供从备份读取的能力,这是提供最终一致性保证的经典案例,其中不一致窗口取决于日志传送的周期。

服务器端一致性

在服务器端,我们需要更深入地了解更新如何流经系统,以了解是什么使得系统的开发人员可以感受到不同的模式。在开始之前,让我们先建立一些定义:

N = 存储数据副本的节点数

W = 更新完成前需要确认收到更新的副本数

R = 通过读取操作访问数据对象时联系的副本数

如果 W + R > N,那么写集和读集始终存在重叠,可以保证强一致性。在实现同步复制技术的主备 RDBMS 场景中:N=2、W=2、R=1,无论客户端从哪个副本读取,总能得到一致的结果。在启用了从备份读取的异步复制中,N=2、W=1、R=1。这种情况下 R + W = N,无法保证一致性。

这些基本仲裁协议(quorum protocols)配置存在的问题是,当系统由于故障而无法写入 W 节点时,写入操作必须失败,这标志着系统不可用。当 N = 3 和 W = 3 且只有两个节点可用时,系统不得不使写入失败。

在高性能和高可用性的分布式存储系统中,副本的数量通常大于 2。仅关注容错的系统通常使用 N = 3(W = 2、R = 2)的配置。需要提供非常高的读取负载服务的系统,通常会复制超出容错所需的数据;N 可以是数十甚至数百节点,R 配置为 1,这样单次读取就能返回结果。关注一致性的系统设置为 W = N 以应对更新,这可能会降低写入成功的概率。对于关注容错但不关注一致性的系统,常见配置是以 W = 1 运行,以获得最小的更新持久性,然后依靠延迟(传播)技术来更新其他副本。

如何配置 N、W 和 R 取决于具体情况以及需要优化的性能路径。在 R = 1 和 N = W 中,我们针对读取情况进行了优化,在 W = 1 和 R = N 中,我们针对快速写入进行了优化。当然,在后一种情况下,出现故障时无法保证持久性,如果 W < (N + 1) / 2,当写集不重叠时,存在冲突写入的可能性。

当 W+R <= N 时出现弱/最终一致性,这意味着读写集有可能不会重叠。如果这是一个经过深思熟虑的配置,而不是基于失败案例,那么将 R 设置为 1 以外的任何值几乎没有意义。这发生在两种非常常见的情况下:第一种是前面提到的用于读扩展的大规模复制;第二种是数据访问更复杂的地方。在简单的键值模型中,比较版本以确定写入系统的最新值很容易,但在返回对象集的系统中,确定正确的最新集更困难。在大多数写入集小于副本集的系统中,有一种机制以延迟方式将更新应用于副本集中的其余节点。在所有副本都被更新之前的时间段是前面讨论的不一致窗口。如果 W+R <= N,则系统容易从尚未收到更新的节点读取数据。

读写一致性、会话一致性和单调一致性能否实现,通常取决于客户端对与执行分布式协议服务器的“粘性”。如果每次都是同一台服务器,那么就比较容易保证读写和单调读写。同一台服务器使得管理负载平衡和容错稍微困难一些,却是一个简单的解决方案。使用具有粘性的会话易于理解,并提供客户可以推理的暴露级别。

有时客户端实现读写和单调读取。通过在写入时添加版本,客户端会丢弃对上次看到的版本之前版本的读取。

当系统中的某些节点无法连接到其他节点,但客户端组可以访问这两个节点集合时,就会发生分区。如果您使用经典的多数仲裁方法,则在另一个分区变得不可用时,具有复制集的 W 个节点的分区可以继续进行更新。读取集也是如此。假设这两个集合重叠,根据定义,少数集合将变得不可用。分区不经常发生,但它们确实发生在数据中心之间以及数据中心内部。

在某些应用程序中,任何分区的不可用都是不可接受的,重要的是可以让访问该分区的客户端继续运行。在这种情况下,双方分配一组新的存储节点来接收数据,并在分区愈合时执行合并操作。例如,在亚马逊内部,购物车使用一种永远写入的系统;在分区的情况下,即使原始购物车位于其他分区上,客户也可以继续将商品放入购物车。一旦分区恢复,购物车应用程序将协助存储系统合并购物车。

亚马逊 Dynamo

亚马逊的 Dynamo 就是这样一个系统,将所有这些特性都置于应用程序体系结构的显式控制之下。它是一个键值存储系统,跟 AWS(Amazon’s Web Service)一样,在亚马逊电子商务平台的服务内部广泛使用。Dynamo 的设计目标之一是允许应用程序的所有者、创建 Dynamo 存储系统实例者,在一致性、持久性、可用性和性能之间进行权衡,而 Dynamo 存储系统通常跨越多个数据中心。

总结

在大规模可靠的分布式系统中,有两个必须容忍数据不一致的原因:在高并发条件下改善读写性能;以及处理大多数模型会导致部分系统不可用的分区情况,即使节点已启动并正在运行。

不一致性是否可接受取决于客户端应用程序。在所有情况下,开发人员都需要意识到,一致性保证是由存储系统提供的,在开发应用程序时需要加以考虑。最终一致性模型有许多实际的改进,例如会话一致性和单调读,它们给开发人员提供了更好的工具。很多时候,应用程序能够毫无问题地处理存储系统的最终一致性保证。一个特别流行的例子是一个网站,在这个网站中我们可以有用户感知一致性的概念。在这种情况下,不一致窗口需要小于客户加载下一个页面的预期时间。使得在预期下一次读取之前,将更新传播到整个系统。

本文的目标是提高对工程系统复杂性的认识,这些系统需要在全球范围内运行,并且需要仔细调优,以确保它们能够提供应用程序所需的持久性、可用性和性能。系统设计者拥有的工具之一就是一致性窗口的长度,在此期间,系统的客户端可能会接触到大规模系统工程的实相。

参考文献

  1. Brewer, E. A. 2000. Towards robust distributed systems (abstract). In proceedings of the 19th annual acm symposium on principles of distributed computing (July 16-19, Portland, Oregon): 7
  2. A Conversation with Bruce Lindsay. 2004. ACM Queue 2(8): 22-33.
  3. DeCandia, G., Hastorun, D., Jampani, M., Kakulapati, G., Lakshman, A., Pilchin, A., Sivasubramanian, S., Vosshall, P., Vogels, W. 2007. Dynamo: Amazon’s highly available key-value store. In Proceedings of the 21st ACM symposium on operating systems principles (Stevenson, Washington, October).
  4. Gilbert , S., Lynch, N. 2002. Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant Web services. ACM SIGACT News 33(2).
  5. Lindsay, B. G., Selinger, P. G., et al. 1980. Notes on distributed databases. In distributed data bases, ed. i. W. Draffan and F. Poole, 247-284. Cambridge: Cambridge University Press. Also available as IBM Research Report RJ2517, San Jose, California (July 1979).

原文链接:http://www.allthingsdistributed.com/2008/12/eventually_consistent.html

本文作者 : cyningsun

本文地址https://www.cyningsun.com/06-26-2021/eventually-consistent-cn.html

版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!


目录
相关文章
|
数据库管理 Ruby
Transaction recovery: lock conflict caught and ignored
Transaction recovery: lock conflict caught and ignored环境:RAC 4节点、oracle 11.2.0.4、redhat 5.9 64bit 问题描述: 1.
1843 0
2.4 Scattering Reads
2.4 Scattering Reads
48 0
2.5 Gathering Writes
2.5 Gathering Writes
66 0
|
关系型数据库 MySQL
Consistent Nonlocking Reads,Locking Reads 和Phantom Rows
以Consistent Nonlocking Reads,Locking Reads为突破点,用简单的例子来说明mysql常用的事务隔离级别(READ COMMITTED, REPEATABLE READ)和lock(record lock,gap lock,next-key lock, Insert Intention Lock)的关系
Consistent Nonlocking Reads,Locking Reads 和Phantom Rows
|
存储 算法
Consistent Hashing算法
前几天看了一下Memcached,看到Memcached的分布式算法时,知道了一种Consistent Hashing的哈希算法,上网搜了一下,大致了解了一下这个算法,做下记录。     数据均衡分布技术在分布式存储系统中非常重要,数据分布越均匀,系统的总体性能就越好。
888 0
|
SQL 数据库 关系型数据库