英文版:http://www.julianbrowne.com/article/viewer/brewers-cap-theorem
中文版:http://blog.sina.com.cn/s/blog_493a8455010161hi.html
中文版原文如下:
1976年6月4号,周5,在远离音乐会大厅的一个楼上的房间内,在位于Manchester的Lesser Free TradeHall,Sex Pistols乐队(注:Sex Pistols的经理人Malcolm McLaren2010.4.8去世)开始了他们的第一次演出(注:规模太小称不上演唱会)。关于当晚谁出席了那场演出有些混乱,部分是因为6周后的另一场音乐会,但最主要的还是因为,这场演出被认为是永久改变西方音乐文化的一场演出。这场演出是如此的重要且富有象征意义,以至于DavidNolan写了一本书:《我发誓我在那里:那场改变了世界的演出》,对那些声称自己看过那场演出的人做出判断。因为6月4号被认为是punk摇滚的开始。
在这之前(大约是在1971年左右)曾有一些protopunk乐队,例如New York Dolls和VeletUnderground,但从音乐民俗学来说,是SexPistols开启了这场革命,在这场运动中驱动了Buzzcocks乐队的吉他,The Smiths乐队哀怨的哭诉,TheFall乐队的电子切音,Joy Division和SimplyRed乐队华丽的升调(我猜你不了解所有的含义)(注:我缺乏摇滚方面的知识,这部分翻的不是很满意,好在不影响大局,有punk摇滚知识的同学可以提供帮助)
2000年7月19号,周三,对主流文化来说并不(象前者一样)具有同样的重要性,但这个日子对互联网公司来说,和25年SexPistols对音乐所做的一样,具有同样的影响。这就是Eric Brewer在ACM研讨会上关于分布式计算的原则(Principlesof Distributed Computing)所做的开题演讲 (keynote speech)。
SexPistols向同时代的人展示了几乎无限制的扩展远比学院派的结构主义重要的多,给任何人3根弦以及一些许可就可以组建一支乐队。EricBrewer,在那时被称为Brewer猜想:
认为当应用系统变得越来越web化,应当放弃对数据一致性(dataconsistency)的担忧,因为要想获 得这种新的分布式系统的高可用性(highavailability),确保数据一致性是我们无法做到的,这样给予任 何人3台服务器和一双关注客户体验的眼睛就可以建立一家互联网公司.
(本人注:在互联网架构设计当中,一般不会放弃可用性这一指标,而可用性主要是通过冗余来实现的,所以不可避免的就会产生网络分区,即选择了可用性,也就选择了分区容忍性,所以没有办法确保数据的一致性(这里是指强一致性)) 。
Brewer的信徒(当天就有的和后来皈依的)包括像Amazon,EBay和Twitter这类公司
2年后,2002年,麻省理工(MIT)的Seth Gilbert和NancyLynch,理论上证明了Brewer猜想是正确的,就此Brewer定理(Theorem)诞生了。
Brewer(CAP)定理
那么到底Brewer的定理是什么,为何它足以和1976年Manchester的punk演出媲美?
Brewer 在2000年的演讲是基于他在UCBerkley的理论工作以及主持Inktomi(期间)的观察,是通过数年前Brewer和其他人,在如何构建高伸缩性系统(highlyscalable system)时所做出的各种折衷方案的讨论(例如:SOSP(Symposium on OperatingSystem Principles)的1997年的Cluster-Based Scalable NetworkService和1999年的Harvest, yield, and scalable tolerantsystem)就像其他的许多思想,因此这个演讲的内容并不是全新的,它是许多聪明人的共同成果(我确信Brewer会很快说明这一点)。
Brewer认为在分布式的环境下设计和部署系统时,有3个核心的系统需求(systemicrequirements),以一种特殊的关系存在。(他主要是谈论Web类的应用,但如今非常多的公司业务是多站点/多国家的,因此该理论同样适用于你的数据中心/LAN/WAN的设计)这3个核心的需求是:Consistency(一致性),Availability(可用性)和PartitionTolerance(分区容忍性),赋予了该理论另外一个名字 - CAP。
(引用:在某时刻如果满足AP,分隔的节点同时对外服务但不能相互通信,将导致状态不一致,即不能满足C;如果满足CP,网络分区的情况下为达成C,请求只能一直等待,即不满足A;如果要满足CA,在一定时间内要达到节点状态一致,要求不能出现网络分区,则不能满足P。)
要想将该理论和现实的联系起来,让我们举一个简单的例子:
你想购买一套托尔斯泰的《战争与和平》,以便在明天开始的长假中有可读的东西。然而你最喜欢的网上书店只有一本库存了。你进行搜索,确认书可以在你出发前送到,然后将书加入你的购物车。
接着你想起来还有一些其他的东西要买,所以继续浏览网站(你是否在网站只买一件东西?当然要充分利用包裹的费用了)。但当你查看某个防晒霜的客户反馈时,国内某个地方的某个人,进入网站,将那本书加入到自己的购物车,然后直接付款(他们急需用一本书垫桌子)。
Consistency(数据一致性)
如果系统对一个写操作返回成功,那么之后的读请求都必须读到这个新数据;如果返回失败,那么所有读操作都不能读到这个数据,对调用者而言数据具有强一致性(strong consistency) (又叫原子性 atomic、线性一致性 linearizable consistency)(原文是:A service that is consistent operates fully ornot at all)。
(本人注:在分布式系统当中有A、B两个节点,A、B两个节点都要对同一个数据V进行读写,数据一致性要求,A、B两个节点对V的读取都是同一个相同的值,很容易想到的解决方案就是将数据V放到一个公共的地方,如数据库里面。A、B对公共节点进行读取这样就能达到数据一致性的要求。但是这样公共节点就成为了一个单点,有单点故障的危险,如果公共节点失效了,那整个系统就失效了,这就牺牲了可用性。)
Gilbert和Lynch在他们的证明中使用“atomic”而不是consistent,技术上来讲更准确,因为严格来说,当用在数据库事务的属性中时,consistent是指ACID中的C,其含义是如果数据违反了某些预设的约束(presetconstraints)就不能被持久化(persisted)。
但如果你将其认为是分布式系统中的一个预设约束:
不允许同一数据有不同的值,那么我认为这个抽象概念的漏洞就被堵住了(而且,如果Brewer使用atomic这个词,就会被称为AAP定理,那每次我们读它的时候都会被送进医院)(注:我估计是有口吃加白痴的嫌疑)。
在前面购书的例子中:
- 你将书加入购物车或无法加入。支付成功或不成功。你无法部分加入或部分支付一本书。
- 库存中只有一本书,当天只有一个人能得到它。
如果2个客户都可以完成订单流程(如完成支付),那么仓库中的和系统中的不一致性就会导致问题。
在这个例子中也许并不是个大问题:某个人在假期中会很无聊或摆弄防晒霜,但如果将其扩大到数千个不一致性,并且涉及到金钱(例如:金融交易中关于买卖的东西和交易记录的内容不一致)就会是个大问题。
也许我们可以利用数据库来解决一致性问题。
在(购书的)订单流程中的某个点减少《战争与和平》的库存记录。当其他的客户到达这个点的时候,书架空了,订单流程将会通知客户,而不会进行到支付环节。
这样第一个操作顺利完成,第二个操作则不会完成。数据库非常适合这种情况,因为数据库关注ACID属性,并且通过隔离性(Isolation)来保证一致性,这样当第一个客户会使得库存记录减1,同时购物车的记录加1,任何中间状态同第二个客户都是隔离的,当然第二个客户必须等待几百毫秒以便数据存储达到一致状态。
Availability(可用性)
可用性只是意味着服务是可用的(可以完成如上的操作或不完成)。
(本人注:可用性要求服务在任何时该都是可用的,这就要求系统当中不应该有单点的存在,通常可用性都是通过冗余的方式来实现的, 在实际评估可用性的时候都是通过几个9来表示的,如3个9就要求系统 在一年当中99.9%是可用的,100%的可用性是不可能存在的。)
当你购书时期望得到反馈,而不是浏览器报告网站无法连接的信息。Gilbert和Lynch在其CAP定理的证明中很好地指出了,可用性通常在你最需要的时刻背弃你。网站通常在业务最繁忙的时刻挂掉,因为网站压力最大。一个他人无法访问的服务对任何人都没有价值。
Partition Tolerance(分区容忍性)
如果你的应用和数据库运行在一个机器上(忽略规模的问题并假定你的代码都没问题),你的服务器是作为一种原子处理单元(atomicprocessor):要么工作要么不工作(例如:如果down机就不可用,但也不会造成数据不一致问题)一旦开始将数据和逻辑分布在不同的节点上,就有形成partition的风险。假定网线被切断,partition就形成了,节点A无法和节点B通讯。由于Web提供的这种分布式能力,临时的partition是一个常见的情况,如之前说所的,在全球化的有多个数据中心的公司中这并不罕见。Gilbert 和Lynch是这样定义partitiontolerance的,
除了整个网络的故障外,其他的故障(集)都不能导致整个系统无法正确响应。(No set of failuresless than total network failure is allowed to cause the system torespondincorrectly),
(本人注:分布式系统主要是用来解决大规模的应用,在大规模应用当中,不可能由单一主机提供全部服务,即在分布式系统当中,分区是必然存在的。分区容忍性是指在发生网络分区的时候,我们该怎么办?强调在发生网络分区的时候系统也要能够提供正确的响应。
要实现分区容忍性通常要求在本地保存一份数据副本或者是将所有的服务都放到同一台机器上面,这样就不会发生网络分区的情况(这样做严重影响了可扩展性,当前系统是不是在分布式环境下也是一个值得商权的问题),所以在CAP当中的P是必选项,我们只有在CP,和AP当中做出选择。)
请注意Brewer的注释,单节点partition就等同于服务器crash,因为如果无法连接它,那它就和不存在一样.
定理的重要性
CAP定理在应用系统规模化时最有效。在低压力的情况下,小的延迟(以便数据库达到一致的状态)还不足以对总体的性能或用户体验造成影响。你所承担的负载分布,可能都是出于系统管理的原因?
但随着活动的增加,吞吐量的上限(pinch-points)将会限制增长并产生错误。必须等待网页的返回是一种情况,另一种情况则是在你输入信用卡信息后遇到“HTTP 500 java.lang.schrodinger.purchasingerror”,你就想知道你是否付了钱但无法得到东西,还是没付钱,或者这只是交易中一个不重要的错误。谁知道呢?你不太可能继续下去,很有可能到别的地方购物,或更有可能给银行打电话。
不管是那种情况对业务都没有好处。Amazon声称每0.1秒的响应延迟都会导致1%的销售降低。Google说他们注意到0.5秒的延迟会使流量减少15%。
我之前曾就scalability写过一些东西,不想在这里重复,只想指出2点:
第一点是,解决scale问题看起来是一个架构方面的问题,但最初的讨论却不是,而是业务决策。我已经很厌倦听到技术人员说,因为当前的流量,这样或那样的方案不能用。并不是说技术人员错了,通常他们讲的非常正确,是由于从一开始所限定的scale隐含地做了revenue决策-这一问题应该在业务分析时明确地决定下来。
第二点是,一旦你开始讨论如何scale业务系统,大致会落到2种意识形态阵营中:
数据库派和非数据库派。
对于数据库派来说,毫无疑问,钟爱数据库技术,并倾向于谈论optimistic locking和sharding这类的东西来解决scale问题,并将数据库作为系统的核心。
非数据库派会倾向于尽可能多的在数据库环境(避免关系世界)之外管理数据以解决scale问题。
我认为,可以公平地说,前一派人对CAP定理的热情肯定不如后一派(尽管他们在讨论定理)。这是因为,如果你必须在consistency,availability,partition tolerance三者中放弃一个,大多数会选择放弃consistency,而consistency是数据库存在的理由。(选择的)逻辑,无疑,是availability和partition tolerance能够使你赖以赚钱的系统生存下去,而不一致性感觉好像是你可以用好的设计来解决的问题。
和IT中的其他事情一样,这不是非黑即白的问题。EricBrewer在其PODC演讲的第13页slide中,当比较ACID和其非正式的对应物的BASE时,甚至说“我认为这是一个系列(spectrum)”(注:这里光谱有一个系列的含义,是指ACID和BASE是不对立的)。如果你对这个主题感兴趣(有些超出我在这里讨论的范围了),你可以从一篇叫做,“Designand Evaluation of a Continuous Consistency Model for ReplicatedService ”的论文开始,该文由Haifeng Yu和Amin Vahdat编写。大家不可以将CAP解读为暗示数据库的消亡。
尽管这样,双方都认同scale的解决之道是分布式的并行计算,而不是曾经认为的超级计算机。90年代中期进行的Network ofWorkstations项目受到了Eric Brewer的影响,并最终导致了CAP定理的诞生,因为他在一个关于Inktomi andthe Internet Bubble 的介绍中说到,答案总是并行处理:
如果不通过并行的方式,你就没有机会,在合适的时间内解决问题。和其他许多事情一样。如果是个很大的项目,会需要很多人来完成它。因此,如果想建造一个桥梁,就需要很多建筑工人。这就是并行处理。因此问题会演变为“如何将并行处理和internet结合在一起”
图片证明
这里有一个简单的图片证明,因为我发现用图片会比较好理解。多数情况下我使用和Gilber和Lynch相同的术语,以便和他们的论文联系起来。
上图显示了网络中的两个节点N1,N2。他们共享同一数据V(库存中《战争与和平》的数量),其值为V0。N1上有一个算法A,我们可以认为A是安全,无bug,可预测和可靠的。N2上有一个类似的算法B。在这个例子中,A写入V的新值而B读取V的值。
正常情况下(sunny-dayscenario),过程如下:(1)A写入新的V值,我们称作v1。(2)N1发送信息给N2,更新V的值。(3)现在B读取的V值将会是V1。
如果网络断开(partions)(意味着从N1无法发送信息到N2)那么在第3步的时候,N2就会包含一个步一致的V值。
希望看上去很明白。即使将其scale到几百个事务(transaction)中,这也会成为一个大问题。如果M是一个异步消息,那么N1无法知道N2是否收到了消息。即使M是保证能发送的(guaranteeddelivery),N1也无法知道是否消息由于partition事件的发生而延迟,或N2上的其他故障而延迟。即使将M作为同步(synchronous)信息也不能解决问题,因为那将会使得N1上A的写操作和N1到N2的更新事件成为一个原子操作(atomicoperation),而这将导致同样的等待问题,该问题我们已经讨论过(或更糟)。Gilbert和Lynch已经证明,使用其他的变种方式,即使是部分同步模型(每个节点上使用安排好的时钟)也无法保证原子性(atomicity)。
因此,CAP告诉我们,如果想让A和B是高可用(highlyavailable)的(例如,以最小的延迟(latency)提供服务)并且想让所有的N1到Nn(n的值可以是数百甚至是上千)的节点能够冗余网络的partitions(丢失信息,无法传递信息,硬件无法提供服务,处理失败),那么有时我们就得面临这样的情况:某些节点认为V的值是V0(一本《战争与和平》的库存)而其他节点会认为V的值是V1(《战争与和平》的库存为0)
我们都希望所有的事情是结构化的,一致的且和谐的,就像70年代早期的progrock乐队,但我们面临的是一些punk风格的混乱。事实上,尽管有可能会吓到我们的祖母,但一旦你了解了它就还OK,因为2者可以非常愉快地在一起工作。
让我们从事务(transactional)的角度快速分析一下。
如果我们有个事务(例如:一组围绕着persistent数据项V的工作单元)a,a1是写操作,a2是读操作。在一个local的系统中,可以利用数据库中的简单锁(simplelocking)的机制方便地处理,隔离(isolating)a2中的读操作,直到a1的写成功完成。然而,在分布式的模型中,需要考虑到N1和N2节点,中间的消息同步也要完成才行。除非我们可以控制a2何时发生,我们永远无法保证a2可以读到a1写入的数据。所有加入控制的方法(阻塞,隔离,中央化的管理,等等)会要么影响partition tolerance,要么影响a1(A)和a2(B)的可用性。
CAP选择
当处理CAP的问题时,你会有几个选择。最明显的是:
- 放弃Partition Tolerance:如果你想避免partition问题发生,你就必须要阻止其发生。一种做法是将所有的东西(与事务相关的)都放到一台机器上。或者放在像rack这类的atomically-failling单元上。无法100%地保证,因为还是有可能部分失败,但你不太可能碰到由partition问题带来的负面效果。当然,这个选择会严重影响scale限制。
- 放弃Availability:相对于放弃partition tolerance来说,其反面就是放弃availability。一旦遇到partition事件,受影响的服务需要等待数据一致,因此在等待期间就无法对外提供服务。在多个节点上控制这一点会相当复杂,而且恢复的节点需要处理逻辑,以便平滑地返回服务状态。
- 放弃Consistency:或者如同Werner Vogels所提倡的,接受事情会变得“最终一致(EventuallyConsistent)”(2008年12月更新)。Vogels的文章值得一读。他比我在这里讨论了更多的操作方面的细节。许多的不一致性并不比你想的需要更多的工作(意味着持续的consistency或许并不是我们所需要的)。在购书的例子中,如果一本库存的书,接到了2个订单,第二个就会成为备份订单。只要告知客户这种情况(请记住这是一种罕见的情况),也许每个人都会高兴的。
- 引入(jump)BASE.有一种架构的方法(approach)称作BASE(Basically Available,Soft-state,Eventuallyconsistent)支持最终一致概念的接受。
BASE(注:化学中的含义是碱),如其名字所示,是ACID(注:化学中的含义是酸)的反面,但如果认为任何架构应该完全基于一种(BASE)或完全基于另一种(ACID),就大错特错了。这一点是需要谨记重点,尤其是这个行业的“一边倒(ooohshiny,注:这个完全意译了)”的习惯性的采用策略。这里,我要遵从Brewer教授自己的观点,他就本文通过email表达了自己的观点(comment):
如您所指出的,术语BASE第一次出现是在1997年的SOSP文章中。那一年,我和我的学生在他们的办公室中,一起造了这个词。我承认这有些人为的因素,但ACID也是一样的--远超人们所能意识到的,所以我们人为还行。JimGray和我讨论了这些缩写,他欣然认可ACID也有些扭曲(stretch)–A和D(的概念)有相当多的重复部分,C至多也是含糊不清的。但这对术语暗示了一系列的理念(idea ofspectrum),这是PODC演讲中的一个重要观点,你正确地指出了这一点。
EBay的DanPritchett有一篇关于BASE的很棒的介绍 (presentation)。
Guy Pardon,atomikos的CTO写了一篇他称作“CAP解决之道(证实Brewer的错误)”的文章,提出了一种架构方法,可以达到Consistency,Availability和Partition-tolerance,当然附带了一些说明(显然你不可能在同一时刻满足全部的3个要求)。值得一读,Guy雄辩地表达了(在该领域)相反的观点。
总结
在Consistency,Availability和Partition-tolerance中,你只能保证2点,这是确实的,并且已经被这个星球上最成功的网站证实了。如果对网站是有效的,我看不出在企业环境中,在日常的工作中,不考虑同样的折衷设计的理由。如果业务方面明确表明不需要上规模(scale)那好,有简单的解决方案,但这是值得讨论的。在任何情况下,这些讨论都是针对特定操作的适合的设计,而不是庐山(注:shebang取意译)全貌。正如Brewer在其邮件中所说的:“唯一的我可以加入的是同一服务的不同部分可以选择这一系列(spectrum)中的不同的点”有时,无论scale的代价如何,你绝对需要一致性,因为缺少它的风险太大了。
这些天,我说得有些过,说Amazon和EBay没有scalability问题,我认为他们的确有这类问题,但他们现在有办法解决该问题。这也是为何他们可以自由讨论这些问题的原因。不论他们现在是何规模(结合他们早就公布的数字)只会越来越大。一旦规模上来,你的问题就会转到(shift)诸如操作维护,监控,发布软件的更新等等- 当然(这些问题)都很难解决,但值得,尤其当你因此获得现金流(revenue stream)。
参考
- HP接纳CAPd定理,白皮书的标题为分布式数据没有免费的午餐
- Sussex大学计算机科学讲义,关于分布式事务和网络partitions
- Jens Alfke的关于数据库,scaling和Twitter的好文
- Pat Helland的关于分布式事务和SOA的Microsoft论文,叫做数据在外和数据在外 ,他随后将其和CAP理论关联了起来
- 另一套计算机科学方面课程slides ,这一次是来自Virginia的George Mason大学,是关于分布式软件系统和CAP定理以及ACID和BASE两大阵营的对比
- 在英国1976年6月4号被认为是Punk摇滚诞生的日子。感谢Charlie Dellacona指出在美国Ramones普遍认为是从1974年就开启了这一运动,尽管他们正式的punk唱片是在同时发行的
- 感谢Hiroshi Yuki,提供了本文的日文版译本
- 感谢哦Daniel Cohen,提供了分为两 部分的希伯来版译本
- 感谢Wang Qi,提供了本文的中文版译本