谈到 NoSQL,一定会提及一致性(Consistency),按照 CAP 定理,有些 NoSQL 数据库放弃了一致性,但是 NoSQL 放弃是必然的选择吗?
从 1970’s,关系型数据库(RDB,Relational Database)被发明以来,关系型数据库就是构建应用的通常的选择。关系型数据库对用户提供 ACID 保证,非常方便开发者使用。从 1990’s 开始,NoSQL 系统开始出现。NoSQL 系统是一类对立于关系数据库的数据库系统,他们从架构上放弃了传统的关系型数据库的的关系模型和 SQL 的接口。
与 NoSQL 系统相伴而来的 2 个词是 BASE 和 CAP,这 2 个词对分布式系统有着非常深远的影响。我相信就是在这 2 个词的影响下,很多 NoSQL 系统从架构的初始就放弃了一致性(consistency)选择了一种最终一致性(Eventual consistency)和可用性 (Availability)。虽然我非常认同 CAP 和 BASE 这 2 个词,但是我不认为在 CAP 和 BASE 的作用下,NoSQL 系统选择放弃一致性是一个必然的事情。
首先来回顾一下 CAP 和 BASE 这 2 个概念的历史。这 2 个概念都是由 Eric Brewer 提出的,Brewer 目前是 Google 公司的基础设施部门(Infrastructure)的副总裁(VP,Vice President)。在 1997 年,在 SOSP(Symposium on Operating Systems Principles) 上,名为的演讲 [1] 总结了 Brewer 等人的近期工作,演讲中说他们正在工作的集群服务并没有采用当时公认的具有 ACID 特性的关系型数据库作为架构,而是在架构上放弃了关系型数据库的 ACID 特性。并且为他们的这个架构选择构造了一个新的词 BASE,BASE 这个词的选择有刻意为之成分,ACID 在英语里有酸性的意思,而 BASE 有碱性的意思,很明显 BASE 是与?ACID 对立的。
ACID 和 BASE 分别是如下单词的首字母缩写:
ACID:Atomicity, Consistency, Isolation, Durability
BASE: Basically Available, Soft State, Eventual Consistency
BASE 主张放弃掉 ACID,主要是放弃 ACID 中的 Consistency,并且让系统达到基本可用(Basically Available),柔性状态(Soft State),最终一致(Eventual Consistency)。系统构建者可以不仅仅选择 ACID,BASE 也称为一种选择,也就是在 ACID 和 BASE 中选择其一。本质上来讲,就是在 ACID 代表的一致性 (Consistency) 和 BASE 代表的可用性(Availability)二者之间做出选择。虽然在 BASE 提出时,还没有明确说明在一致性和可用性间做出架构选择,但是已经为后面 CAP 的提出做好了伏笔。
到 2000 年,Brewer 在 PODC(Principles of Distributed Computing)做了名为 [2] 的演讲,演讲的主旨是阐明如何构建健壮的分布式系统。在这次演讲中,Brewer 近一步分析比较了 ACID 和 BASE,并且抽象了 ACID 和 BASE 的核心特性,也就是 ACID 的一致性(Consistency),BASE 的可用性(Availability),并且扩展了第 3 个维度,也就是网络分区(Network Partition),从而提出了CAP 猜想,这个猜想说:
在分布式系统中,最多能同时满足以下 3 个属性中的 2 个:
C (Consistency), A (Availability), P (Tolerance to network Partitions)
根据这个猜想,会存在 3 类系统:
放弃 P,系统具有 CA 特性,这类系统诸如单机数据库
放弃 A,系统具有 CP 特性,这类系统诸如分布式数据库、分布式锁
放弃 C,系统具有 AP 特性,这类系统诸如 web caching、DNS
可用性是非常重要的一个特性,特别是在互联网行业中,服务宕机对商业的影响是非常大的,所以依据 CAP 定理放弃一致性也就是自然的选择了。特别是在 Amazon 的 CTO Werner Vogels 详细介绍了 Eventually Consistent[5] 和 Amazon 的 Dynamo 系统的论文 [12] 发表后,大量追求可用性放弃一致性的 NoSQL 系统出现。
到了 2002 年,GilBert 和 Lynch[3],重新定义了 CAP 这 3 个属性(重新定义的属性比 Brewer 猜想中的属性的范围小了很多),并且证明了 CAP 这 3 个属性不能同时达到,从而将 CAP 猜想变成了CAP 定理。
CAP 定理中的 3 个属性定义如下 [3,6]:
Consistency: 是指原子一致性(Atomic consistency)或者线性一致性(linearizable consistency),这是一种非常高的一致性级别,很少有系统能够达到。
Availability: 是指完全的可用性,也就是每个到达每个没有宕机的节点上的读写请求都能在一个合理的时间返回一个响应。这里的关键点是每个请求到达每个非宕机的节点。这也是一种非常高的可用性水平,也很少有系统能够达到。
Partition Tolerant: 是指系统能够在出现网络分区的情况下,继续正确响应,即保持系统该有的特性,或者说保持一致性或者可用性。
Glibert 和 Lynch 重新定义的 CAP 定理非常严谨,但是只证明了 3 个属性不能同时具有。然而 Brewer 猜想中的 3 个属性的定义、3 选 2 的描述,3 分的分类法(AP,CP,CA3 种分类)却不是非常严谨,这也是 CAP 出现之后,很多人怀疑和挑战 CAP 的原因。Brewer 在 2012 年重新写了一篇文章 [4],也承认最初的 CAP 表述非常令人误解。事实上,CAP 定理的适用范围是非常小的。 虽然 CAP 从出生开始就有很多问题,但是它仍然推动了 NoSQL 运动,很多系统架构者依据 CAP 定理,主动放弃了一致性,但实际上,很多时候这些系统都是不满足 CAP 定理的适用范围的。
CAP 的故事到此并未完结,2017 年,Brewer 已经是 Google 公司的基础设施(Infrastructure)部门的副总裁(VP,Vice President)了,并且这时 Google 公司的第一代 Spanner 系统已经诞生 [9]。Brewer 写了一篇文章讲述了 Google 公司的 Spanner 系统 [7],并且近一步阐述了按照 CAP 定理 Spanner 是一个什么样特性的系统。在文中,Brewer 指出 Spanner 系统说是 " 实际上的 CA"(effectively CA)系统。从架构上来讲,Spanner 是一个 CP 系统,也就是说当出现网络分区时,Spanner 选择的是保证数据的一致性,放弃可用性的。但实际上,Spanner 是具有非常高可用性效果的一个系统,从架构上 Spanner 没有达到 CAP 定理要求的那种完全可用性,但是也达到非常高的可用性,由于采用多副本的设计,个别副本出现网络分区,并不影响用户能感知到的可用性。按 CAP 定理的定义,当这些个别副本出现网络分区时,这些节点是不可用的,也就是系统没有达到完全可用性。但是此时的用户请求是可以被其他副本服务的,此时服务是可用的,也就是说用户仍然感知到 Spanner 是可用的。所以说用户感知的可用性和 CAP 定理中的可用性不是一个概念。我们追求的应该是用户感知的可用性。
用户可感知的可用性,通常用 SLA 来表示,也就是我们通常说的几个 9 的可用性。Brewer 在文章中也给出了 Google 关于 Spanner 系统的 SLA 的数据,从数据我们可以看到,由于网络分区导致的服务可用的比例是比较小的,有很大一部分导致服务不可用的原因是诸如软件 bug、配置错误、运维误操作等导致的。也就是说,即便在架构上采用了达到 CAP 定理要求的可用性,实际用户可感受到的服务可用性,也就 SLA 也不会提高多少。这也是我从业这么多年的一个体会,系统的不稳定更多来自系统开发者的日常失误,加强代码质量,加强开发流程规范,加强生产运维规范,更能大大提高系统的可用性。所以,在架构层面,因为可用性放弃一致性往往是得不偿失的。
云计算的大潮下,不放弃一致性也是非常明智的。一个托管在云上的数据存储服务,如果你放弃了一致性选择可用性,用户是感受不明显,因为使用者不会对架构设计采用达到的 CAP 定理的可用性而买单,用户只会为你的服务达到 SLA 买单。然而数据存储服务是否具有一致性,用户是能够非常明显的感受到的。Amazon 公司的内部的 Dynamo[12] 在架构上是可以达到 CAP 定理中的可用性要求的,但是 Amazon 在 AWS 云上售卖的 DynamoDB 并不是采用的这一架构,也许就是出于这个原因 [10]。
那么我们选择一致性得到的好处是什么那?很多时候,说到一致性时,都会拿金融和钱相关的例子来说明一致性的必要性,但是我相信金融行业并不强依赖一致性 [10]。我认为一致性给我带来的是开发的方便性。Brewer 虽然提出了 BASE 概念,但是他并没有详细阐述这个概念。2008 年 EBay 公司的 Dan Pritchett,写了一遍文章 [8],通过举例详细阐述了在放弃了 ACID 以后,如何采用 BASE 架构实现相同的需求,向我们推荐了 BASE 这种架构模式。通过这篇文章,我们我可以看到如果放弃了 ACID 而选择 BASE 的话,本来一个非常简单的功能,需要加入消息队列等手段才能让系统达到最终一致性,应用的整体架构复杂了很多。
类似于 Pritchett 文章中说明的一样,使用不具有一致性的 NoSQL 系统,你需要仔细甄别你的使用场景,判断你的使用场景是否可以让你放弃一致性。即便你要使用 BASE 架构,也不是简单地采用一个具有最终一致性的 NoSQL 系统,替换掉 ACID 数据库就好了,你需要设计好各种手段,处理掉具有最终一致性的 NoSQL 系统带来的异常,让你的整个应用达到柔性状态和最终一致。BASE 中所说的最终一致和很多 NoSQL 系统所具有的最终一致有些细微的差别。这个差别简单来说是,BASE 中所说的最终一致是保证系统状态是正确的;而很多 NoSQL 系统最终一致只保证最终一致,但是不保证这个状态是你想要的正确的状态 [11]。
最后,个人的一个观点是,如果一个 NoSQL 系统做为缓存使用,为了追求低延时,可以放弃一致性,大数据和离线计算的场景类似于这种场景,很多 NoSQL 系统是非常适用的;但是如果 NoSQL 系统作为数据库来用,那么这个 NoSQL 系统最好不要因为可用性放弃一致性,同时通过多副本技术和良好运维达到实际的高可用性,即达到实际上的 CA(effectively CA),这样可以大大降低使用者的使用负担。
由于篇幅所限,本文中关于一致性、CAP、BASE、ACID 的很多技术细节的阐述未能详尽,拟另行成文讨论。成文仓促,有错漏之处欢迎各位大神指正。
作者简介:陈东明,饿了么北京技术中心架构组负责人,负责饿了么的产品线架构设计以及饿了么基础架构研发工作。曾任百度架构师,负责百度即时通讯产品的架构设计。具有丰富的大规模系统构建和基础架构的研发经验,善于复杂业务需求下的大并发、分布式系统设计和持续优化。个人微信公众号 dongming_cdm。
1.Cluster-Based Scalable Network Services, A. Fox et al., 1997.
2.Towards Robust Distributed Systems, E. Brewer, 2000.
3.Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant web services, Seth Gilbert, Nancy Lynch, 2002
4.CAP twelve years later: How the “rules” have changed, Eric Brewer, 2012
5.Eventually Consistent - Revisited, Werner Vogels, 2008
6.Understanding the CAP Theorem, Akhil Mehra,
7.Spanner, TrueTime & The CAP Theorem, Eric Brewer, 2017,
8.Base: An Acid Alternative,Dan Pritchett,
9.Spanner: Google’s Globally-Distributed Database,2012
10.Designing Data-Intensive Applications, Martin Kleppmann
11.Jepsen: Cassandra,Kyle Kingsbury,
12.Dynamo: Amazon’s Highly Available Key-value Store, Giuseppe DeCandia et al., 2007
作者:cadem