在上一篇《Paxos、Raft不是一致性算法/协议?》中,皮皮简单地聊了聊一致性(Consistency)与共识(Consensus)的区别。本文再来继续简单聊一聊CAP。不管大家有没有深入了解过分布式系统,相信对CAP应该还是有个比较熟悉的印象。

CAP定理起源于加州大学柏克莱分校(University of California, Berkeley)的计算机科学家埃里克·布鲁尔(Eric Brewer)在2000年的分布式计算原理研讨会(PODC)上提出的一个猜想[1]。在2002年,麻省理工学院(MIT)的赛斯·吉尔伯特(Seth Gilbert)和南希·林奇(Nancy Lynch)发表了布鲁尔猜想的证明,使之成为一个定理[2]。CAP定理也称为布鲁尔定理(Brewer’s theorem)。

对于CAP的具体含义,我们不妨先来看看维基百科对于的解释。

(上图中维基百科中关于CAP解释的截图,这里内容重放一下)在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer’s theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency) (等同于所有节点访问同一份最新的数据副本)
  • 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据)
  • 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。)

针对维基百科的释义,可用性指的是能获取到“可以不是最新但要求是非错的”响应,那么如果我们访问每一个节点都获取到了错误的响应,那么这在CAP中怎么解释呢?A不满足,C中也没有相关的说明。显然,维基百科中对于一致性的释义并不完整。

对于分区容错性,维基百科中也并没有直接给出一个精确的定义,而是以“就实际效果而言。。”的衬托手法来释义,其实是一种含糊其辞的表现。

对于CAP的定义,个人觉得左耳朵耗子在《分布式系统架构经典资料[3]》一文中的解释比较简洁明了+到位:

  • 一致性(Consistency):每次读取要么获得最近写入的数据,要么获得一个错误。
  • 可用性(Availability):每次请求都能获得一个(非错误)响应,但不保证返回的是最新写入的数据。
  • 分区容忍性(Partition tolerance):尽管任意数量的消息被节点间的网络丢失(或延迟),系统仍继续运行。

这里以维基百科为例其实是精心挑选的,因为维基百科本身还具有一定的“权威性”,这里我“稍微”批评了一下它对于CAP解释的不到位(有一说一,维基百科中对于CAP的定义也是整合了的许多权威资料而来的,只能说整理之人未能完全地融会贯通)。很多不太具备“权威性”的文章对于CAP的解释就更不用说了,比如“三者只可择其二”,初看上去没毛病,其实有很多漏洞。

初看去没错在一个分布式系统中,网络故障和节点宕机是常态,因此网络分区是一定会出现的。在网络分区发生时,根据业务需求,系统需要在可用性和一致性之间二选一:

  • 优先保证可用性。网络分区使得有些节点不可达,导致系统不能够及时同步数据。尽管被请求节点试图返回其可见范围内的最新数据,但仍不能保证该数据是全局最新的,即牺牲一致性保证可用性。
  • 优先保证一致性。网络分区使得被请求节点不能够保证数据全局最新时,返回一个出错信息给用户;或者什么也不返回,直到客户端超时。

实则有漏洞三者择其二是要我们将系统分为CA、CP或者AP中的一种,比如传统的单机数据库可以看做是CA。其实,系统并不需要在任何时候都必须抛弃 CAP 中的一个。比如系统网络状况良好时,并不需要在三者间进行取舍,此时不需要分区容错,可兼顾一致性和可用性。即:三者可兼顾其三。再换种思路来讲。现实中的可用性并不完全与 CAP 可用性 (CAP-availability) 一致。应用程序的可用性可能是通过 SLA 来衡量的 (例如, 99.9% 的合法请求必须在1秒内成功返回响应), 但是这样的 SLA 指标 CAP 可用 (CAP-available) 和 CAP 不可用 (CAP-unavailable) 的系统都能满足。现实中的一致性也可类推。很多系统在CAP定理下,既不可用也不一致,严格来讲,顶多算个“P”。即:三者只得其一。

说到对于CAP的吐槽,神书《数据密集型应用系统设计》的作者Martin Kleppmann的观点尤为经典,他曾发文《Please stop calling databases CP or AP[4]》来数落过CAP。在文章的开头就针对Jeff Hodges的文章《Distributed Systems for Young Bloods[5] 》进行了反驳。

Jeff Hodges在文章中建议用CAP定理来评价一个系统,他认为可以直接将一个系统描述为CP、AP亦或者是CA。Martin Kleppmann对此说道:“我同意 Jeff 的所有其他观点, 但关于 CAP 定理, 我持有不同意见。CAP 定理过于精简, 且被广泛误解, 导致它对描述一个系统没有多大用处。所以我恳请大家最好还是放弃 CAP 定理并停止引用和讨论。并且我们要用更精确的术语来权衡系统。”

《Please stop calling databases CP or AP》这篇文章篇幅较长,需要静下心来细看。比如,Martin Kleppmann认为CAP的定义非常的狭隘:

  • 在CAP中,一致性其实指的是线性一致性,这是非常困难的,且不说在分布式环境下,就算是单机多核的情况下,也要通过内存屏障来处理。
  • 可用性在 CAP 中定义为 “系统中的非故障节点针对收到的每个请求必须做出非错误响应”,这里的问题在于, 某个节点能够处理请求是不够的, 任何非故障节点都要能够处理请求。许多所谓的 “高可用” (即低停机时间) 系统都不符合这种可用性的定义。
  • 分区容错性 (Partition Tolerance)(文章中还多附带了一句:terribly mis-named,PS:有些英文直译成中文会失去一些味道) 基本上意味着你的通信建立在可能会延迟或丢包的异步通信网络上。我们所使用的互联网和数据中心等都具备这个特性, 所以在这个问题上其实没有任何选择.

再比如,CAP 中定理完全没有提到延迟 (latency), 大家关注的可不仅仅是可用性. 实际上, CAP 可用的系统允许响应无限慢, 并且这样仍然可以称作 “可用” 。如果加载一个页面要2分钟, 用户可就不会认为你的系统 “可用”了.

在CAP发表的第12年头,即2012年, Eric Brewer 也承认 CAP 具有误导性而且过于简单化:自打引入 CAP 理论的十几年里,设计师和研究者已经以它为理论基础探索了各式各样新颖的分布式系统,甚至到了滥用的程度。CAP 理论的表述很好地服务了它的目的,即开阔设计师的思路,在多样化的取舍方案下设计出多样化的系统。在过去的十几年里确实涌现了不计其数的新系统,也随之在数据一致性和可用性的相对关系上产生了相当多的争论。“三选二”的公式一直存在着误导性,它会过分简单化各性质之间的相互关系。

Eric Brewer 还阐述了他的新观点:由于分区很少发生,那么在系统不存在分区的情况下没什么理由牺牲 C 或 A。其次,C 与 A 之间的取舍可以在同一系统内以非常细小的粒度反复发生,而每一次的决策可能因为具体的操作,乃至因为牵涉到特定的数据或用户而有所不同。最后,这三种性质都可以在程度上衡量,并不是非黑即白的有或无。可用性显然是在 0% 到 100% 之间连续变化的,一致性分很多级别,连分区也可以细分为不同含义,如系统内的不同部分对于是否存在分区可以有不一样的认知。要探索这些细微的差别,就要突破传统的分区处理方式,而这是一项根本性的挑战。因为分区很少出现,CAP 在大多数时候允许完美的 C 和 A。但当分区存在或可感知其影响的情况下,就要预备一种策略去探知分区并显式处理其影响。这样的策略应分为三个步骤:探知分区发生,进入显式的分区模式以限制某些操作,启动恢复过程以恢复数据一致性并补偿分区期间发生的错误。

更多具体内容参考英文原文:http://cs609.cs.ua.edu/CAP12.pdf,中文翻译版为:《[CAP理论十二年回顾:”规则”变了](https://www.infoq.cn/article/cap-twelve-years-later-how-the-rules-have-changed/)》

为什么写这些内容?我查阅过很多资料,一是觉得大多数资料说的不清不楚,有明显的漏洞;二是,随着分布式理论与实践的发展,有些东西的含义在慢慢的变化,在迭代升级。越深究越模糊,错亦对时对亦错,对亦错时错亦对。

其实,对CAP的理解,我们可以简单地记一下一致性、可用性、分区容错性这些词汇,也可以记一下经典的三角关系。不过,CAP的意义在于设计分布式系统时需要考虑取舍,不是一个严格的分类方式,并且现代分布式也有更好的模型。CAP 在分布式系统未火热之时,归纳出了分布式系统设计中所需权衡重要的方向。在云计算、大数据如火如荼的今天,一大批优秀的分布式系统涌现出来,给了我们更多的系统设计的考虑方向和实践细节。如今做系统设计时,不用太过拘泥于 CAP 原则,根据所面对业务场景,大胆进行取舍即可。

总结一句话:管TM的什么CAP、BASE,安安稳稳CRUD。

除了最后一句,如果其它观点有错误,欢迎在留言区留言探讨。^-^

参考资料

[1]

猜想: https://people.eecs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf[2]

定理: https://web.archive.org/web/20080908063921/http://lpd.epfl.ch/sgilbert/pubs/BrewersConjecture-SigAct.pdf[3]

分布式系统架构经典资料: https://www.infoq.cn/article/2018/05/distributed-system-architecture[4]

Please stop calling databases CP or AP: https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html[5]

Distributed Systems for Young Bloods: https://www.somethingsimilar.com/2013/01/14/notes-on-distributed-systems-for-young-bloods/

Comments are closed.