CAP定理指在设计分布式系统时,一致性(Consistent)、可用性(Availability)、Partition Tolerance(分区容忍性)三个属性不可能同时满足,该定理也叫做布鲁尔定理。CAP定理明确了分布式系统所能实现系统的局限性,目前互联网中的很多分布式系统是基于首要满足可用性和分区容忍性而设计的。在这里,不打算提及目前火热的Cassandra、Voldemort等分布式存储系统,而是打算介绍一下CAP定理。
形式化描述
一致性:所有在分布式系统上的操作有一个总体上的顺序,每一个操作看起来就像是在一个单独的瞬间完成的。这就要求分布式系统的运行就像是在一个单节点上一样,在一个时间响应一个操作。
可用性:对于一个可用性的分布式系统,每一个非故障的节点必须对每一个请求作出响应。也就是,该系统使用的任何算法必须最终终止。当同时要求分区容忍性时,这是一个很强的定义:即使是严重的网络错误,每个请求必须终止。
分区容忍性:为了定义分区容忍性,假定网络满足如下条件:网络是可能丢失从一个节点发往另一个节点的任意消息,当网络被分区(隔断)时,所有从一个分区的节点发往另一个分区的消息将会丢失。一致性要求每个响应必须是一致的,即使系统内部的消息没有被正确地发送。可用性要求从客户端接收请求的任一节点必须被响应,即使任意的消息可能没有被正确地发送。
异步网络
在异步网络模型中,没有统一时钟,所有节点仅根据接收到的消息和本地的计算进行决策。
定理一:
在一个异步网络模型中,没有可能实现一个满足以下属性的读写数据对象:
1、可用性
2、一致性
对于所有对等运算(包括消息会丢失的)
证明:
假设存在一个算法A满足这些条件:一致性、可用性、分区容忍性。我们构造一次A的执行,包括一个返回非一致结果的请求。假设网络包含至少两个节点,那么它可以被分为不相关的非空集合:{G,H}。假设所有G和H之间的通讯消息都丢失,这是可能的。如果这时在G上有一个写操作,接着H上有一个读操作,那么读操作将无法返回早些的写操作。■
推论一:
在一个异步网络模型中,没有可能实现一个满足以下属性的读写数据对象:
1、可用性,所有对等运算
2、一致性,所有对等运算,但消息不会丢失
证明:
主要问题是在异步网络模型中一个算法没有办法去判断一个消息是否丢失或者在传输通道中被延迟。因此,如果在运算中不会丢失任何消息的前提下存在一个能够保证一致性的算法,那么该算法也能够在所有运算(消息可能丢失)情况下保证一致性。这将与定理一矛盾。■
部分同步网络
假设一个部分同步的网络模型,在这里,所有的节点都有一个时钟,并且所有的时钟以一个相同的速度增长。然而,这些时钟并不是同步的,在相同的时间,它们显示不同的时间值。事实上,时钟扮演计时器的角色:处理器可以根据本地状态变量去衡量流逝了多少时间。一个本地的计时器可以用来调度某事件之后的多长时间间隔进行另一个操作。进一步地,假设每一个消息要么在给定的时间s内到达,要么丢失。并且,所有的节点在给定时间t内处理完一个接收到的消息。
定理二:
在一个部分同步网络模型中,没有可能实现一个满足以下属性的读写数据对象:
1、可用性
2、一致性
对于所有对等运算(包括消息会丢失的)
证明:
证明方法与定理一一样。■
但是在部分同步模型中,类似与异步模型推论一的结论就不存在了,因此推论一的假设基于节点无法判断一个消息是否丢失。而在部分同步模型中,存在部分同步算法可以在所有消息传送正常的情况下返回一致性的数据,而仅仅在消息丢失时返回非一致性数据。对于读或写请求,节点发送一个消息给另一个节点,如果消息返回了,那么节点发送请求的数据;如果消息在给定的2s+t时间内没有返回,那么该节点断定消息丢失了,节点就可能返回一个不一致的请求数据。
理论参考价值
在Google使用廉价的PC机搭建了强大的、高可靠的计算和存储平台之后,互联网公司一致性地选择使用PC集群支撑全部的业务,这个理论指明了实现满足可用性、分区容忍性的分布式系统是可行的,并且该分布式系统在没有故障的情况下可以提供良好的一致性读写。
参考
Lynch, Nancy, and Seth Gilbert. “Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services.” ACM SIGACT News, v. 33 issue 2, 2002, p. 51-59.
Amazon和EBay一直在喝的酷爱(kool aid)饮料。
by Julian Browne on 2009.1.11 (经Julian授权翻译此文,原文参见)
1976年6月4号,周5,在远离音乐会大厅的一个楼上的房间内,在位于Manchester的Lesser Free Trade Hall,Sex Pistols乐队(注:Sex Pistols的经理人Malcolm McLaren 2010.4.8去世)开始了他们的第一次演出(gig,注:规模太小称不上演唱会)。关于当晚谁出席了那场演出有些混乱,部分是因为6周后的另一场音乐会,但最主要的还是因为,这场演出被认为是永久改变西方音乐文化的一场演出。这场演出是如此的重要且富有象征意义,以至于David Nolan写了一本书:《我发誓我在那里:那场改变了世界的演出》,对那些声称自己看过那场演出的人做出判断。因为6月4号被认为是punk摇滚的开始。
在这之前(大约是在1971年左右)曾有一些protopunk乐队,例如New York Dolls和Velet Underground,但从音乐民俗学来说,是Sex Pistols开启了这场革命,在这场运动中驱动了Buzzcocks乐队的吉他,The Smiths乐队哀怨的哭诉,The Fall乐队的电子切音,Joy Division和Simply Red乐队华丽的升调(我猜你不了解所有的含义)(注:我缺乏摇滚方面的知识,这部分翻的不是很满意,好在不影响大局,有punk摇滚知识的同学可以提供帮助)
2000年7月19号,周三,对主流文化来说并不(象前者一样)具有同样的重要性,但这个日子对互联网公司来说,和25年Sex Pistols对音乐所做的一样,具有同样的影响。这就是Eric Brewer在ACM研讨会上关于分布式计算的原则(Principles of Distributed Computing)所做的开题演讲 (keynote speech)。
Sex Pistols向同时代的人展示了几乎无限制的狂躁远比学院派的结构主义重要的多,给任何人3根弦以及一些许可就可以组建一支乐队。Eric Brewer,在那时被称为Brewer猜想,认为当应用系统变得越来越web化,应当放弃对数据一致性(data consistency)的担忧,因为要想获得这种新的分布式系统的高可用性(high availability),确保数据一致性是我们无法做到的,这样给予任何人3台服务器和一双关注客户体验的眼睛就可以建立一家互联网公司。Brewer的信徒(当天就有的和后来皈依的)包括像Amazon,EBay和Twitter这类公司
2年后,2002年,麻省理工(MIT)的Seth Gilbert和Nancy Lynch,理论上证明了Brewer猜想是正确的,就此Brewer定理(Theorem)诞生了。
那么到底Brewer的定理是什么,为何它足以和1976年Manchester的punk演出媲美?
Brewer 在2000年的演讲是基于他在UC Berkley的理论工作以及主持Inktomi(期间)的观察,是通过数年前Brewer和其他人,在如何构建高伸缩性系统(highly scalable system)时所做出的各种折衷方案的讨论(例如:SOSP(Symposium on Operating System Principles)的1997年的Cluster-Based Scalable Network Service和1999年的Harvest, yield, and scalable tolerant system)就像其他的许多思想,因此这个演讲的内容并不是全新的,它是许多聪明人的共同成果(我确信Brewer会很快说明这一点)。
Brewer认为在分布式的环境下设计和部署系统时,有3个核心的系统需求(systemic requirements),以一种特殊的关系存在。(他主要是谈论Web类的应用,但如今非常多的公司业务是多站点/多国家的,因此该理论同样适用于你的数据中心/LAN/WAN的设计)
这3个核心的需求是:Consistency,Availability和Partition Tolerance,赋予了该理论另外一个名字 - CAP。
要想将该理论和现实的联系起来,让我们举一个简单的例子:你想购买一套托尔斯泰的《战争与和平》,以便在明天开始的长假中有可读的东西。然而你最喜欢的网上书店只有一本库存了。你进行搜索,确认书可以在你出发前送到,然后将书加入你的购物车。接着你想起来还有一些其他的东西要买,所以继续浏览网站(你是否在网站只买一件东西?当然要充分利用包裹的费用了)。但当你查看某个防晒霜的客户反馈时,国内某个地方的某个人,进入网站,将那本书加入到自己的购物车,然后直接付款(他们急需解决桌子摇晃的问题,其中一条桌脚比其他的短的多)。
一旦开始将数据和逻辑分布在不同的节点上,就有形成partition的风险。假定网线被切断,partition就形成了,节点A无法和节点B通讯。由于Web提供的这种分布式能力,临时的partition是一个常见的情况,如之前说所的,在全球化的有多个数据中心的公司中这并不罕见。
Gilbert 和Lynch是这样定义partition tolerance的
除了整个网络的故障外,其他的故障(集)都不能导致整个系统无法正确响应。(No set of failures less than total network failure is allowed to cause the system to respond incorrectly)
请注意Brewer的注释,单节点partition就等同于服务器crash,因为如果无法连接它,那它就和不存在一样。
CAP定理在应用系统规模化时最有效。在低压力的情况下,小的延迟(以便数据库达到一致的状态)还不足以对总体的性能或用户体验造成影响。你所承担的负载分布,可能都是出于系统管理的原因。?
但随着活动的增加,吞吐量的上限(pinch-points)将会限制增长并产生错误。必须等待网页的返回是一种情况,另一种情况则是在你输入信用卡信息后遇到 “HTTP 500 java.lang.schrodinger.purchasingerror”,你就想知道你是否付了钱但无法得到东西,还是没付钱,或者这只是交易中一个不重要的错误。谁知道呢?你不太可能继续下去,很有可能到别的地方购物,或更有可能给银行打电话。
不管是那种情况对业务都没有好处。Amazon声称每0.1秒的响应延迟都会导致1%的销售降低。Google说他们注意到0.5秒的延迟会使流量减少20%。
我之前曾就scalability写过一些东西,不想在这里重复,只想指出2点:第一点是,解决scale问题看起来是一个架构方面的问题,但最初的讨论却不是,而是业务决策。我已经很厌倦听到技术人员说,因为当前的流量,这样或那样的方案不能用。并不是说技术人员错了,通常他们讲的非常正确,是由于从一开始所限定的scale 隐含地做了revenue决策-这一问题应该在业务分析时明确地决定下来。
第二点是,一旦你开始讨论如何scale业务系统,大致会落到2种意识形态阵营中:数据库派和非数据库派。
对于数据库派来说,毫无疑问,钟爱数据库技术,并倾向于谈论optimistic locking和sharding这类的东西来解决scale问题,并将数据库作为系统的核心。
非数据库派会倾向于尽可能多的在数据库环境(避免关系世界)之外管理数据以解决scale问题。
我认为,可以公平地说,前一派人对CAP定理的热情肯定不如后一派(尽管他们在讨论定理)。这是因为,如果你必须在consistency,availability,partition tolerance三者中放弃一个,大多数会选择放弃consistency,而consistency是数据库存在的理由。(选择的)逻辑,无疑,是availability和partition tolerance能够使你赖以赚钱的系统生存下去,而不一致性感觉好像是你可以用好的设计来解决的问题。
和IT中的其他事情一样,这不是非黑即白的问题。Eric Brewer在其PODC演讲的第13页slide中,当比较ACID和其非正式的对应物的BASE时,甚至说“我认为这是一个系列(spectrum)”(注:这里光谱有一个系列的含义,是指ACID和BASE是不对立的)。如果你对这个主题感兴趣(有些超出我在这里讨论的范围了),你可以从一篇叫做,“Design and Evaluation of a Continuous Consistency Model for Replicated Service ”的论文开始,该文由Haifeng Yu和Amin Vahdat 编写。大家不可以将CAP解读为暗示数据库的消亡。
尽管这样,双方都认同scale的解决之道是分布式的并行计算,而不是曾经认为的超级计算机。90年代中期进行的Network of Workstations项目受到了Eric Brewer的影响,并最终导致了CAP定理的诞生,因为他在一个关于Inktomi and the Internet Bubble 的介绍中说到,答案总是并行处理:
如果不通过并行的方式,你就没有机会,在合适的时间内解决问题。和其他许多事情一样。如果是个很大的项目,会需要很多人来完成它。因此,如果想建造一个桥梁,就需要很多建筑工人。这就是并行处理。因此问题会演变为“如何将并行处理和internet结合在一起”
这里有一个简单的图片证明,因为我发现用图片会比较好理解。多数情况下我使用和Gilber 和Lynch相同的术语,以便和他们的论文联系起来。
上图显示了网络中的两个节点N1,N2。他们共享同一数据V(库存中《战争与和平》的数量),其值为V0。N1上有一个算法A,我们可以认为A是安全,无bug,可预测和可靠的。N2上有一个类似的算法B。在这个例子中,A写入V的新值而B读取V的值。
正常情况下(sunny-day scenario),过程如下:(1)A写入新的V值,我们称作v1。(2)N1发送信息给N2,更新V的值。(3)现在B读取的V值将会是V1。
如果网络断开(partions)(意味着从N1无法发送信息到N2)那么在第3步的时候,N2就会包含一个步一致的V值。
希望看上去很明白。即使将其scale到几百个事务(transaction)中,这也会成为一个大问题。如果M是一个异步消息,那么N1无法知道N2是否收到了消息。即使M是保证能发送的(guaranteed delivery),N1也无法知道是否消息由于partition事件的发生而延迟,或N2上的其他故障而延迟。即使将M作为同步(synchronous)信息也不能解决问题,因为那将会使得N1上A的写操作和N1到N2的更新事件成为一个原子操作(atomic operation),而这将导致同样的等待问题,该问题我们已经讨论过(或更糟)。Gilbert 和Lynch已经证明,使用其他的变种方式,即使是部分同步模型(每个节点上使用安排好的时钟)也无法保证原子性(atomicity)。
因此,CAP告诉我们,如果想让A和B是高可用(highly available)的(例如,以最小的延迟(latency)提供服务)并且想让所有的N1到Nn(n的值可以是数百甚至是上千)的节点能够冗余网络的partitions(丢失信息,无法传递信息,硬件无法提供服务,处理失败),那么有时我们就得面临这样的情况:某些节点认为V的值是V0(一本《战争与和平》的库存)而其他节点会认为V的值是V1(《战争与和平》的库存为0)
我们都希望所有的事情是结构化的,一致的且和谐的,就像70年代早期的prog rock乐队,但我们面临的是一些punk风格的混乱。事实上,尽管有可能会吓到我们的祖母,但一旦你了解了它就还OK,因为2者可以非常愉快地在一起工作。
让我们从事务(transactional)的角度快速分析一下。
如果我们有个事务(例如:一组围绕着persistent数据项V的工作单元)a,a1是写操作,a2是读操作。在一个local的系统中,可以利用数据库中的简单锁(simple locking)的机制方便地处理,隔离(isolating)a2中的读操作,直到a1的写成功完成。然而,在分布式的模型中,需要考虑到N1和N2节点,中间的消息同步也要完成才行。除非我们可以控制a2何时发生,我们永远无法保证a2可以读到a1写入的数据。所有加入控制的方法(阻塞,隔离,中央化的管理,等等)会要么影响partition tolerance,要么影响a1(A)和a2(B)的可用性。
当处理CAP的问题时,你会有几个选择。最明显的是:
如您所指出的,术语BASE第一次出现是在1997年的SOSP文章中。那一年,我和我的学生在他们的办公室中,一起造了这个词。我承认这有些人为的因素,但ACID也是一样的--远超人们所能意识到的,所以我们人为还行。Jim Gray和我讨论了这些缩写,他欣然认可ACID也有些扭曲(stretch)– A和D(的概念)有相当多的重复部分,C至多也是含糊不清的。但这对术语暗示了一系列的理念(idea of spectrum),这是PODC演讲中的一个重要观点,你正确地指出了这一点。
EBay的Dan Pritchett有一篇关于BASE的很棒的介绍 (presentation)。
在Consistency, Availability和Partition-tolerance中,你只能保证2点,这是确实的,并且已经被这个星球上最成功的网站证实了。如果对网站是有效的,我看不出在企业环境中,在日常的工作中,不考虑同样的折衷设计的理由。如果业务方面明确表明不需要上规模(scale)那好,有简单的解决方案,但这是值得讨论的。在任何情况下,这些讨论都是针对特定操作的适合的设计,而不是庐山(注:shebang取意译)全貌。正如Brewer在其邮件中所说的:“唯一的我可以加入的是同一服务的不同部分可以选择这一系列(spectrum)中的不同的点”有时,无论scale的代价如何,你绝对需要一致性,因为缺少它的风险太大了。
这些天,我说得有些过,说Amazon和EBay没有scalability问题,我认为他们的确有这类问题,但他们现在有办法解决该问题。这也是为何他们可以自由讨论这些问题的原因。不论他们现在是何规模(结合他们早就公布的数字)只会越来越大。一旦规模上来,你的问题就会转到(shift)诸如操作维护,监控,发布软件的更新等等 - 当然(这些问题)都很难解决,但值得,尤其当你因此获得现金流(revenue stream)。