目录

第五章 最终一致性入门

最终一致性入门指南介绍了最终一致性的概念,并解释了它的一些应用方式。本指南运用 CAP 定理,重点阐述了在分布式系统中维护数据一致性所面临的挑战,并解释了最终一致性如何成为一种可行的替代方案。

在最终一致性数据库中,对同一数据值的并发请求可能会返回不同的值。这种情况是暂时的,因为这些值最终会达到“最终”一致性。

最终一致性源于数据更新方式的选择。它是分布式事务的替代方案。它可以带来更好的可扩展性、更高的性能和更低的成本。是否采用最终一致性取决于业务决策。

在任何时刻,最终一致性数据库的大部分数据都是一致的,只有少量值仍在更新。数据值不一致的情况通常只会持续几秒钟,但这并非必然。这取决于应用程序,并且会根据当前情况而变化。

CAP 定理与最终结果

布鲁尔 CAP 定理(简称 CAP 定理)考虑了分布式应用程序中数据的三种可能保证:一致性 (Consistency)、可用性 (Availability) 和 分区容错性 (Partition Tolerance)(虽然拼写为 CAPT,但通常使用更易读的 CAP)。一致性 意味着所有节点都能获得相同的结果;可用性 意味着客户端可以持续访问(即使系统出现部分故障);分区容错性 意味着即使应用程序中的节点与网络断开连接且无法通信,也能正确运行。CAP 定理指出,应用程序在这三种保证中只能选择两种。

当数据位于单个节点上时,保证一致性很容易,但一旦数据分布在各个节点上,就需要考虑分区容错性。如果节点由于故障而无法相互通信,或者通信速度不足以满足性能和可扩展性目标,会发生什么情况?我们可以做出不同的权衡。对于云原生应用而言,一种常见的选择是优先考虑分区容错性和可用性,而放弃即时一致性的保证。

不保证即时一致性的应用被称为最终一致性。当业务价值(风险、缺点或成本)被认为优于即时一致性时,使用最终一致性就很有意义。

虽然这种方法对于关系数据库领域的用户来说可能不太熟悉,但最终一致性可以成为一项强大的特性,从而实现更好的可扩展性。最终一致性并非缺陷或设计缺陷。如果使用得当,它反而是一项优势。

最终一致性示例

“最终一致性”这个术语相对较新,但其概念却由来已久。域名系统 (DNS) 就是一个古老的例子。DNS 负责互联网名称解析,将易于理解的网址(例如 http://www.pageofphotos.com)转换为计算机可识别的 IP 地址(例如 12.34.56.789)。当域名的 IP 地址发生更改时,通常需要几个小时才能将更新传播到互联网上的所有 DNS 服务器(这些服务器可能缓存了旧地址)。这被认为是一种合理的权衡:IP 地址更改的频率并不高,因此我们可以容忍偶尔出现的不一致,以换取卓越的可扩展性。在 IP 地址更改后但尚未完全传播之前,部分用户会被定向到旧网站的 IP 地址,而部分用户则会被定向到新网站的 IP 地址。

照片页​​面 (PoP) 应用程序之所以具有最终一致性,是因为照片上传后到网站访问者看到照片之间存在延迟。此外,一些访问者可能会比其他访问者更早看到照片。部分原因是由于跨数据中心的数据复制,部分原因是内部处理,例如新上传照片的导入过程。

Windows Azure、Amazon Web Services、Google App Engine 和其他云平台在各种情况下都具有最终一致性。例如,激活 CloudFront(Amazon 的全球 CDN 服务)和 Traffic Manager(Windows Azure 的全球负载均衡服务)等全球服务后,需要几分钟时间才能将其传播到世界各地的节点。

CAP 定理将这些概念形式化,并在云分布式系统中得到广泛应用,也开始被一些数据库所采用。

关系型 ACID 和 NoSQL 基本

传统的关系型数据库提供四项所谓的 ACID 保证:

原子性 (Atomicity)
事务要么全部完成,要么全部不完成。

一致性 (Consistency)
数据始终符合模式约束。

隔离性 (Isolation)
对同一数据进行更改的事务按顺序执行。

持久性 (Durability)
已提交的更改不会丢失。

这些保证源于数据库运行在单节点上的时代。如果数据库是分布式的,这些保证会变得更加复杂和昂贵。

对于单节点应用程序,CAP 定理并不重要,因为无需考虑分区容错性。随着数据库变得更加分布式(集群或具有地理位置分散的故障转移节点),CAP 定理就显得尤为重要。

CAP 定理告诉我们,必须从三个保证中选择两个,这三个保证可以简写为 CA、AP 和 CP。这三种组合会产生不同的行为。这里我们将重点关注 AP(可用性和分区容错性),也称为最终一致性。

根据定义,最终一致性数据库不支持 ACID 保证,但支持 BASE。BASE 数据库的特点是:

基本可用 (Basically Available)
即使数据过时,系统也会响应。

软状态 (Soft State)
状态可能不一致,但可以被纠正。

最终一致性 (Eventually Consistent)
允许任何单个数据更改完全传播到整个系统之前存在延迟。

BASE 通常与 NoSQL 数据库相关联,而 NoSQL 数据库服务在云中非常流行。NoSQL,或不仅仅是 SQL (Not Only SQL),是近年来兴起的一种数据库风格。 NoSQL 数据库的设计目标是实现极高的扩展性,但代价是牺牲了传统关系型数据库的一些高级功能。例如,它们的事务处理能力通常有限,并且不具备 ACID 特性。值得注意的是,它们通常支持分片,这将在数据库分片模式(第 7 章)中进一步探讨。

与你在高中化学课上学到的酸和碱不同,ACID 和 BASE 特性可以安全地结合使用,即使在同一个应用程序中也是如此。

最终一致性对应用程序逻辑的影响

前面的示例主要集中在一些我们可能熟悉或觉得直观的最终一致性场景上。但当开发人员在数据库中使用最终一致性时,往往会感到惊讶。我们都习惯于在向数据库写入数据后能够读取到它。但如果数据库是最终一致的,则无法保证这一点。

Google 的 App Engine Datastore 服务和 Amazon 的 S3 存储服务都是最终一致的。有时,您可以选择:Amazon 的 SimpleDB 数据库服务具有可配置的一致性(但性能特征有所不同)。许多 NoSQL 数据库也是最终一致的。

需要注意的是,最终一致性数据库始终支持一定程度的原子性。请查阅最终一致性数据库的文档,了解原子性的具体定义。通常情况下,写入一条记录并更改十个属性的数据库操作会作为一个原子单元进行传播。最终一致性不会扩展到这个原子单元内部。这十个更改不会单独显示,不存在部分更新。所有更新都生效之前,任何更新都是不可见的。

开发人员应该如何处理最终一致性的数据存储?

用户体验考量

有时,一个合理的做法是假装无关紧要,直接使用当前已有的数据。令人惊讶的是,在许多最终一致性数据适用的场景下,这种方法效果非常好。通常,用户根本察觉不到任何区别。

然而,有时这取决于用户是谁。如果用户刚刚更新了数据,那么更重要的是显示用户期望的数据,而不是等待用户最终满意。在这种情况下,用户界面只需更新自身以反映用户最近一次的更改即可。此时,用户界面会故意不从数据库刷新数据,因为它知道数据可能已经过时。

程序差异

数据存储系统各不相同,但也存在一些共同点。乐观并发和“最后写入优先”模型很常见。这两个特性相辅相成,因为它们允许应用程序检索一个值,在内存中更新它,然后根据条件将其写回数据库。条件是原始值的时间戳;如果存储中的时间戳与原始值的时间戳相同,则在此期间没有发生任何更改,因此更新不会丢失数据。

其他系统比“最后写入优先”机制更为复杂。Amazon Dynamo 数据库专为 Amazon.com 的购物车而构建。Dynamo 的设计旨在合并同一购物车的多个版本,例如通过临时系统分区(CAP 定理中的“P”)实现的合并,考虑到其用途,这是一个合理的特性。

如果所有写入操作都指向同一个位置,则处理最终一致性就变得简单。Couchbase 和 MongoDB NoSQL 数据库就是这种情况,它们只允许对特定数据值的写入操作指向主节点。一旦写入,更新后的值就会传播到其他节点,而其他节点不允许对其进行修改。在这些情况下,最终一致性仅在读取操作期间才重要。

总结

CAP 定理提供了理论基础,解释了为什么我们无法在分布式数据库中同时保证一致性和可用性。一个有效的折衷方案是允许最终一致性,以换取更好的可扩展性。判断应用程序数据是否适合采用最终一致性是一个业务决策。这实际上是在显示过时数据和更高效地扩展之间做出选择。

在 GitHub 上查看本页或提交勘误 ↗