分布式系统之CAP理论

  任老师第一节主要讲了分布式系统实现时候面临的八个问题,布置的做业就是这个,查询CAP理论。html

  笔者初次接触分布式,因此本文主要是一个汇总。算法

一.CAP起源

  CAP本来是一个猜测,2000年PODC大会的时候大牛Brewer提出的,他认为在设计一个大规模可扩放的网络服务时候会遇到三个特性:一致性(consistency)、可用性(Availability)、分区容错(partition-tolerance)都须要的情景,然而这是不可能都实现的。以后在2003年的时候,Mit的Gilbert和Lynch就正式的证实了这三个特征确实是不能够兼得的。该理论是NoSQL数据库管理系统构建的基础。数据库

  Consistency、Availability、Partition-tolerance的提法是由Brewer提出的,而Gilbert和Lynch在证实的过程当中改变了Consistency的概念,将其转化为Atomic。Gilbert认为这里所说的Consistency其实就是数据库系统中提到的ACID的另外一种表述:编程

  一个用户请求要么成功、要么失败,不能处于中间状态(Atomic);后端

  一旦一个事务完成,未来的全部事务都必须基于这个完成后的状态(Consistent);缓存

  未完成的事务不会互相影响(Isolated);安全

  一旦一个事务完成,就是持久的(Durable)。网络

  对于Availability,其概念没有变化,指的是对于一个系统而言,全部的请求都应该‘成功’而且收到‘返回’。架构

  对于Partition-tolerance,所指就是分布式系统的容错性。节点crash或者网络分片都不该该致使一个分布式系统中止服务。并发

二.CAP简介

  CAP定律说的是在一个分布式计算机系统中,一致性,可用性和分区容错性这三种保证没法同时获得知足,最多知足两个。

2.1 强一致性 

  强一致性:系统在执行过某项操做后仍然处于一致的状态。在分布式系统中,更新操做执行成功后全部的用户都应该读到最新的值,这样的系统被认为是具备强一致性的。 等同于全部节点访问同一份最新的数据副本;

  All clients always have the same view of the data。

2.2 可用性

  可用性:每个操做老是可以在必定的时间内返回结果,这里须要注意的是"必定时间内"和"返回结果"。必定时间指的是,在能够容忍的范围内返回结果,结果能够是成功或者失败。 对数据更新具有高可用性(A);

  Each client can alwa read and write。

2.3 分区容错性

  分区容错性:理解为在存在网络分区的状况下,仍然能够接受请求(知足一致性和可用性)。这里的网络分区是指因为某种缘由,网络被分红若干个孤立的区域,而区域之间互不相通。还有一些人将分区容错性理解为系统对节点动态加入和离开的能力,由于节点的加入和离开能够认为是集群内部的网络分区。

  Partition Tolerance的意思是,在网络中断,消息丢失的状况下,系统照样可以工做。 以实际效果而言,分区至关于对通讯的时限要求。系统若是不能在时限内达成数据一致性,就意味着发生了分区的状况,必须就当前操做在C和A之间作出选择

2.4 放弃C.A.P

  放弃P:若是想避免分区容错性问题的发生,一种作法是将全部的数据(与事务相关的)都放在一台机器上。虽然没法100%保证系统不会出错,但不会碰到由分区带来的负面效果。固然这个选择会严重的影响系统的扩展性。

  放弃A:相对于放弃“分区容错性“来讲,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务须要等待必定的时间,所以在等待期间系统没法对外提供服务。

  放弃C:这里所说的放弃一致性,并非彻底放弃数据一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,若是同时接受到了两份订单,那么较晚的订单将被告知商品告罄。

  一致性与可用性的决择: 而CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而因为当前的网络硬件确定 会出现延迟丢包等问题,因此分区容忍性是咱们必须须要实现的。因此咱们只能在一致性和可用 性之间进行权衡。

三.基本CAP的证实思路

  CAP的证实基于异步网络,异步网络也是反映了真实网络中状况的模型。真实的网络系统中,节点之间不可能保持同步,即使是时钟也不可能保持同步,全部的节点依靠得到的消息来进行本地计算和通信。这个概念实际上是至关强的,意味着任何超时判断也是不可能的,由于没有共同的时间标准。以后咱们会扩展CAP的证实到弱一点的异步网络中,这个网络中时钟不彻底一致,可是时钟运行的步调是一致的,这种系统是容许节点作超时判断的。

  CAP的证实很简单,假设两个节点集{G1, G2},因为网络分片致使G1和G2之间全部的通信都断开了,若是在G1中写,在G2中读刚写的数据, G2中返回的值不可能G1中的写值。因为A的要求,G2必定要返回此次读请求,因为P的存在,致使C必定是不可知足的。

四.CAP的理解

4.1 流行解释

  目前流行的、对CAP理论解释的情形是从同一数据在网络环境中存在多个副本出发为前提的。为了保证数据不会丢失,同时也是为了增长并发访问量(读写分离),在企业级的数据管理方案中,通常必须考虑数据的冗余存储问题,而这应该是经过在网络上的其余独立物理存储节点上保留另外一份、或多份数据副原本实现的(如附图所示)。由于在同一个存储节点上的数据冗余明显不能解决单点故障问题,这与经过多节点集群来提供更好的计算可用性的道理是相同的。

  如上图的状况,数据在节点A、B、C上保留了三份,若是对节点A上的数据进行了修改,而后再让客户端经过网络对该数据进行读取。那么,客户端的读取操做何时返回呢?

  一种状况是要求节点A、B、C的三份数据彻底一致后返回。也就是说,这时从任何一个网络节点读取的数据都是同样的,这就是所谓的强一致性读。很明显,这时数据读取的Latency要高一些(由于要等数据在网络中的复制),同时A、B、C三个节点中任何一个宕机,都会致使数据不可用。也就是说,要保证强一致性,网络中的副本越多,数据的可用性就越差。

  另外一种状况是,容许读操做当即返回,容忍B节点的读取与A节点的读取不一致的状况发生。这样一来,可用性显然获得了提升,网络中的副本也能够多一些,惟一得不到保证的是数据一致性。固然,对写操做一样也有多个节点一致性的状况,在此再也不赘述。

  能够看出,上述对CAP理论的解释主要是从网络上多个节点之间的读写一致性出发考虑问题的。而这一点,对于关系型数据库意味着什么呢?固然主要是指一般所说的Standby(关于分布式事务,涉及到更多考虑,随后讨论)状况。对此,在实践中咱们大多已经采起了弱一致性的异步延时同步方案,以提升可用性。这种状况并不存在关系型数据库为保证C、A而放弃P的状况;而对海量数据管理的需求,关系型数据库扩展过程当中所遇到的性能瓶颈,彷佛也并非CAP理论中所描述的那种缘由形成的。那么,上述流行的说法中所描述的关系型数据库为保证C、A而牺牲P究竟是在指什么呢? 若是只将CAP看成分布式系统中多个数据副本之间的读写一致性问题的通用理论对待,那么就能够得出结论:CAP既适用于NoSQL数据库,也适用于关系型数据库。它是NoSQL数据库、关系型数据库,乃至一切分布式系统在设计数据多个副本之间读写一致性问题时须要遵循的共同原则。

4.2 形式化描述

  要真正理解 CAP 理论必需要读懂它的形式化描述。 形式化描述中最重要的莫过于对 Consistency, Availability, Partition-tolerance 的准肯定义。

  Consistency (一致性) 实际上等同于系统领域的 before-or-after atomicity 这个术语,或者等同于 linearizable (可串行化) 这个术语。具体来讲,系统中对一个数据的读和写虽然包含多个子步骤而且会持续一段时间才能执行完,可是在调用者看来,读操做和写操做都必须是单个的即时完成的操做,不存在重叠。对一个写操做,若是系统返回了成功,那么以后到达的读请求都必须读到这个新的数据;若是系统返回失败,那么全部的读,不管是以后发起的,仍是和写同时发起的,都不能读到这个数据。

  要说清楚 Availability 和 Partition-tolerance 必需要定义好系统的故障模型。在形式化证实中,系统包含多个节点,每一个节点能够接收读和写的请求,返回成功或失败,对读还要返回一个数据。和调用者之间的链接是不会中断的,系统的节点也不会失效,惟一的故障就是报文的丢失。 Partition-tolerance 指系统中会任意的丢失报文(这和“最终会有一个报文会到达”是相对的)。 Availability 是指全部的读和写都必需要能终止。

  注: “Availability 是指全部的读和写都必需要能终止” 这句话听上去很奇怪,为何不是“Availability 是指全部的写和读都必须成功”? 要回答这个问题,咱们能够仔细思考下“什么是成功”。“成功”必需要相对于某个参照而言,这里的参照就是 Consistency。

4.3 两种重要的分布式场景

  关于对CAP理论中一致性C的理解,除了上述数据副本之间的读写一致性之外,分布式环境中还有两种很是重要的场景,若是不对它们进行认识与讨论,就永远没法全面地理解CAP,固然也就没法根据CAP作出正确的解释。

  1.分布式环境中的事务场景      

  咱们知道,在关系型数据库的事务操做遵循ACID原则,其中的一致性C,主要是指一个事务中相关联的数据在事务操做结束后是一致的。所谓ACID原则,是指在写入/异动资料的过程当中,为保证交易正确可靠所必须具有的四个特性:即原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)和持久性(Durability)。

  例如银行的一个存款交易事务,将致使交易流水表增长一条记录。同时,必须致使帐户表余额发生变化,这两个操做必须是一个事务中所有完成,保证相关数据的一致性。而前文解释的CAP理论中的C是指对一个数据多个备份的读写一致性。表面上看,这二者不是一回事,但实际上,倒是本质基本相同的事物:数据请求会等待多个相关数据操做所有完成才返回。对分布式系统来说,这就是咱们一般所说的分布式事务问题。

  众所周知,分布式事务通常采用两阶段提交策略来实现,这是一个很是耗时的复杂过程,会严重影响系统效率,在实践中咱们尽可能避免使用它。在实践过程当中,若是咱们为了扩展数据容量将数据分布式存储,而事务的要求又彻底不能下降。那么,系统的可用性必定会大大下降,在现实中咱们通常都采用对这些数据不分散存储的策略。

  固然,咱们也能够说,最常使用的关系型数据库,由于这个缘由,扩展性(分区可容忍性P)受到了限制,这是彻底符合CAP理论的。但同时咱们应该意识到,这对NoSQL数据库也是同样的。若是NoSQL数据库也要求严格的分布式事务功能,状况并不会比关系型数据库好多少。只是在NoSQL的设计中,咱们每每会弱化甚至去除事务的功能,该问题才表现得不那么明显而已。

  所以,在扩展性问题上,若是要说关系型数据库是为了保证C、A而牺牲P,在尽可能避免分布式事务这一点上来看,应该是正确的。也就是说:关系型数据库应该具备强大的事务功能,若是分区扩展,可用性就会下降;而NoSQL数据库干脆弱化甚至去除了事务功能,所以,分区的可扩展性就大大增长了。

  2.分布式环境中的关联场景      

  初看起来,关系型数据库中经常使用的多表关联操做与CAP理论就更加不沾边了。但仔细考虑,也能够用它来解释数据库分区扩展对关联所带来的影响。对一个数据库来说,采用了分区扩展策略来扩充容量,数据分散存储了,很显然多表关联的性能就会降低,由于咱们必须在网络上进行大量的数据迁移操做,这与CAP理论中数据副本之间的同步操做本质上也是相同的。

  所以,若是要保证系统的高可用性,须要同时实现强大的多表关系操做的关系型数据库在分区可扩展性上就遇到了极大的限制(即便是那些采用了各类优秀解决方案的MPP架构的关系型数据库,如TeraData,Netezza等,其水平可扩展性也是远远不如NoSQL数据库的),而NoSQL数据库则干脆在设计上弱化甚至去除了多表关联操做。那么,从这一点上来理解"NoSQL数据库是为了保证A与P,而牺牲C"的说法,也是能够讲得通的。固然,咱们应该理解,关联问题在不少状况下不是并行处理的优势所在,这在很大程度上与Amdahl定律相符合。

  因此,从事务与关联的角度来看关系型数据库的分区可扩展性为何受限的缘由是最为清楚的。而NoSQL数据库也正是由于弱化,甚至去除了像事务与关联(全面地讲,其实还有索引等特性)等在分布式环境中会严重影响系统可用性的功能,才得到了更好的水平可扩展性。

  那么,若是将事务与关联也归入CAP理论中一致性C的范畴的话,问题就很清楚了:关于“关系型数据库为了保证一致性C与可用性A,而不得不牺牲分区可容忍性P”的说法即是正确的了。但关于"NoSQL选择了C与P,或者A与P"的说法则是错误的,全部的NoSQL数据库在设计策略的大方向上都是选择了A与P(虽然对同一数据多个副本的读写一致性问题的设计各有不一样),历来没有彻底选择C与P的状况存在。

  如今看来,若是理解CAP理论只是指多个数据副本之间读写一致性的问题,那么它对关系型数据库与NoSQL数据库来说是彻底同样的,它只是运行在分布式环境中的数据管理设施在设计读写一致性问题时须要遵循的一个原则而已,却并非NoSQL数据库具备优秀的水平可扩展性的真正缘由。而若是将CAP理论中的一致性C理解为读写一致性、事务与关联操做的综合,则能够认为关系型数据库选择了C与A,而NoSQL数据库则全都是选择了A与P,但并无选择C与P的状况存在。                        

五.一致性分类 

  对于分布式数据系统,分区容忍性是基本要求,不然就失去了价值。所以设计分布式数据系统,就是在一致性和可用性之间取一个平衡。对于大多数WEB应用,其实并不须要强一致性,所以牺牲一致性而换取高可用性,是多数分布式数据库产品的方向。              

  固然,牺牲一致性,并非彻底无论数据的一致性,不然数据是混乱的,那么系统可用性再高分布式再好也没有了价值。牺牲一致性,只是再也不要求关系型数据库中的强一致性,而是只要系统能达到最终一致性便可,考虑到客户体验,这个最终一致的时间窗口,要尽量的对用户透明,也就是须要保障“用户感知到的一致性”。一般是经过数据的多份异步复制来实现系统的高可用和数据的最终一致性的,“用户感知到的一致性”的时间窗口则取决于数据复制到一致状态的时间。               

  对于一致性,能够分为从客户端和服务端两个不一样的视角。从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题。从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致。一致性是由于有并发读写才有的问题,所以在理解一致性的问题时,必定要注意结合考虑并发读写的场景。

5.1 客户端角度

  从客户端角度,多进程并发访问时,更新过的数据在不一样进程如何获取的不一样策略,决定了不一样的一致性。对于关系型数据库, 要求更新过的数据能被后续的访问都能看到,这是强一致性。若是能容忍后续的部分或者所有访问不到,则是弱一致性。若是通过一段时间后要求能访问到更新后的数据,则是最终一致性。            

  在MongoDB中能够经过配置让复制集成员内部支持强一致性,这时能够设置一个写成功数,只有写操做成功树知足设定的值时才会向客户端返回结果。

  最终一致性根据更新数据后各进程访问到数据的时间和方式的不一样,又能够区分为:因果一致性(CAUSAL CONSISTENCY),若是进程A通知进程B它已更新了一个数据项,那么进程B的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程A无因果关系的进程C的访问遵照通常的最终一致性规则。读己之所写(READ-YOUR-WRITES)一致性,当进程A本身更新一个数据项以后,它老是访问到更新过的值,毫不会看到旧值。这是因果一致性模型的一个特例。会话(SESSION)一致性,这是上一个模型的实用版本,它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证“读己之所写”一致性。若是因为某些失败情形令会话终止,就要创建新的会话,并且系统的保证不会延续到新的会话。单调(MONOTONIC)读一致性,若是进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值以前的值。单调写一致性,系统保证来自同一个进程的写操做顺序执行。要是系统不能保证这种程度的一致性,就很是难以编程了。

  上述最终一致性的不一样方式能够进行组合,例如单调读一致性和读己之所写一致性就能够组合实现。而且从实践的角度来看,这二者的组合,读取本身更新的数据,和一旦读取到最新的版本不会再读取旧版本,对于此架构上的程序开发来讲,会少不少额外的烦恼。

5.2 服务端角度

  从服务端角度,如何尽快将更新后的数据分布到整个系统,下降达到最终一致性的时间窗口,是提升系统的可用度和用户体验很是重要的方面。对于分布式数据系统:N — 数据复制的份数,W — 更新数据是须要保证写完成的节点数,R — 读取数据的时候须要读取的节点数,若是W+R>N,写的节点和读的节点重叠,则是强一致性。例如对于典型的一主一备同步复制的关系型数据库,N=2,W=2,R=1,则无论读的是主库仍是备库的数据,都是一致的。若是W+R<=N,则是弱一致性。例如对于一主一备异步复制的关系型数据库,N=2,W=1,R=1,则若是读的是备库,就可能没法读取主库已经更新过的数据,因此是弱一致性。

  对于分布式系统,为了保证高可用性,通常设置N>=3。不一样的N,W,R组合,是在可用性和一致性之间取一个平衡,以适应不一样的应用场景。若是N=W,R=1,任何一个写节点失效,都会致使写失败,所以可用性会下降,可是因为数据分布的N个节点是同步写入的,所以能够保证强一致性。若是N=R,W=1,只须要一个节点写入成功便可,写性能和可用性都比较高。可是读取其余节点的进程可能不能获取更新后的数据,所以是弱一致性。这种状况下,若是W<(N+1)/2,而且写入的节点不重叠的话,则会存在写冲突。

六.传统数据库与NoSQL数据库

  传统的关系型数据库在功能支持上一般很宽泛,从简单的键值查询,到复杂的多表联合查询再到事务机制的支持。而与之不一样的是,NoSQL系统一般注重性能和扩展性,而非事务机制(事务就是强一致性的体现)。      

  传统的SQL数据库的事务一般都是支持ACID的强事务机制。A表明原子性,即在事务中执行多个操做是原子性的,要么事务中的操做所有执行,要么一个都不执行;C表明一致性,即保证进行事务的过程当中整个数据加的状态是一致的,不会出现数据花掉的状况;I表明隔离性,即两个事务不会相互影响,覆盖彼此数据等;D表示持久化,即事务一量完成,那么数据应该是被写到安全的,持久化存储的设备上(好比磁盘)。         

  NoSQL系统仅提供对行级别的原子性保证,也就是说同时对同一个Key下的数据进行的两个操做,在实际执行的时候是会串行的执行,保证了每个Key-Value对不会被破坏。例如MongoDB数据库,它是不支持事务机制的,同时也不提倡多表关联的复杂模式设计,它只保证对单个文档(至关于关系数据库中的记录)读写的原子性。

  补充:  MPP架构介绍 MPP (Massively Parallel Processing),大规模并行处理系统,这样的系统是由许多松耦合的处理单元组成的,要注意的是这里指的是处理单元而不是处理器。每一个单元内的CPU都有本身私有的资源,如总线,内存,硬盘等。在每一个单元内都有操做系统和管理数据库的实例复本。这种结构最大的特色在于不共享资源。

七.打败CAP

  核心内容就是放松Gilbert和Lynch证实中的限制:“系统必须同时达到CAP三个属性”,放松到“系统能够不一样时达到CAP,而是分时达到”。  

  CAP理论被不少人拿来做为分布式系统设计的金律,然而感受你们对CAP这三个属性的认识却存在很多误区。从CAP的证实中能够看出来,这个理论的成立是须要很明确的对C、A、P三个概念进行界定的前提下的。在本文中笔者但愿能够对论文和一些参考资料进行总结并附带一些思考

  CAP理论的表述很好地服务了它的目的,即开阔设计师的思路,在多样化的取舍方案下设计出多样化的系统。在过去的十几年里确实涌现了不可胜数的新系统,也随之在数据一致性和可用性的相对关系上产生了至关多的争论。“三选二”的公式一直存在着误导性,它会过度简单化各性质之间的相互关系。如今咱们有必要辨析其中的细节。实际上只有“在分区存在的前提下呈现完美的数据一致性和可用性”这种不多见的状况是CAP理论不容许出现的。

  虽然设计师仍然须要在分区的前提下对数据一致性和可用性作取舍,但具体如何处理分区和恢复一致性,这里面有不可胜数的变通方案和灵活度。当代CAP实践应将目标定为针对具体的应用,在合理范围内最大化数据一致性和可用性的“协力”。这样的思路延伸为如何规划分区期间的操做和分区以后的恢复,从而启发设计师加深对CAP的认识,突破过去因为CAP理论的表述而产生的思惟局限。

7.1 为何“三选二”公式有误导性

  理解CAP理论的最简单方式是想象两个节点分处分区两侧。容许至少一个节点更新状态会致使数据不一致,即丧失了C性质。若是为了保证数据一致性,将分区一侧的节点设置为不可用,那么又丧失了A性质。除非两个节点能够互相通讯,才能既保证C又保证A,这又会致使丧失P性质。通常来讲跨区域的系统,设计师没法舍弃P性质,那么就只能在数据一致性和可用性上作一个艰难选择。不确切地说,NoSQL运动的主题实际上是创造各类可用性优先、数据一致性其次的方案;而传统数据库坚守ACID特性(原子性、一致性、隔离性、持久性),作的是相反的事情。下文“ACID、BASE、CAP”小节详细说明了它们的差别。

  “三选二”的观点在几个方面起了误导做用,详见下文“CAP之惑”小节的解释。首先,因为分区不多发生,那么在系统不存在分区的状况下没什么理由牺牲C或A。其次,C与A之间的取舍能够在同一系统内以很是细小的粒度反复发生,而每一次的决策可能由于具体的操做,乃至由于牵涉到特定的数据或用户而有所不一样。最后,这三种性质均可以在程度上衡量,并非非黑即白的有或无。可用性显然是在0%到100%之间连续变化的,一致性分不少级别,连分区也能够细分为不一样含义,如系统内的不一样部分对因而否存在分区能够有不同的认知。

  要探索这些细微的差异,就要突破传统的分区处理方式,而这是一项根本性的挑战。由于分区不多出现,CAP在大多数时候容许完美的C和A。但当分区存在或可感知其影响的状况下,就要预备一种策略去探知分区并显式处理其影响。这样的策略应分为三个步骤:探知分区发生,进入显式的分区模式以限制某些操做,启动恢复过程以恢复数据一致性并补偿分区期间发生的错误。

7.2 解决CAP

  根据一些专家的分析,CAP并非一个严谨的定律,并非牺牲了Consistency,就必定能同时得到Availability和Partition Tolerance。还有一个很重要的因素是Latency,在CAP中并无体现。在如今NoSQL以及其余一些大规模设计时,A和P并非牺牲C或部分牺牲C的借口,由于即便牺牲了C,也不必定A和P,而且C不必定必需要牺牲。

  淘宝一天就处理了1亿零580万,而12306一天处理的交易仅仅166万条 ,若是从并发性上来讲,淘宝的并发量远比12306大,但天猫的商品信息,促销数据均可以作缓存,作CDN,而12306的“商品”是一个个座位,这些座位必须经过后端数据库即时查询出来,状态的一致性要求很高。

  从这点上看,12306的商品信息很难利用到缓存,所以12306查看“商品”的代价是比较大的,涉及到一系列的后端数据库操做,从这个角度讲,12306的复杂度是高于天猫的。 淘宝的商品相对独立,而12306商品之间的关联性很大,因为CAP定律限制,若是其商品的一致性要求太高,必然对可用性和分区容错性形成影响。

  所以,业务设计上,若是找到一条下降一致性要求时,还能保证业务的正确性的业务分拆之路。举个例子,火车票查询时,不要显示多少张,而是显示“有”或“无”,或者显示>100张,50~100,小于50等,这样就能够减少状态的更新频率,充分使用缓存数据。

  CAP 理论说在一个系统中对某个数据不存在一个算法同时知足 Consistency, Availability, Partition-tolerance。注意,这里边最重要和最容易被人忽视的是限定词“对某个数据不存在一个算法”。这就是说在一个系统中,能够对某些数据作到 CP, 对另外一些数据作到 AP,就算是对同一个数据,调用者能够指定不一样的算法,某些算法能够作到 CP,某些算法能够作到 AP。

7.3 作到两项

  要作到 CP, 系统能够把这个数据只放在一个节点上,其余节点收到请求后向这个节点读或写数据,并返回结果。很显然,串行化是保证的。可是若是报文能够任意丢失的话,接受请求的节点就可能永远不返回结果。

  要作到 CA, 一个现实的例子就是单点的数据库。你可能会疑惑“数据库也不是 100% 可用的呀?” 要回答这个疑惑,注意上面说的故障模型和 availability 的定义就能够了。

  要作到 AP, 系统只要每次对写都返回成功,对读都返回固定的某个值就能够了。

若是咱们到这里就以为已近掌握好 CAP 理论了,那么就至关于刚把橘子剥开,就把它扔了。

  CAP 理论更重要的一个结果是, 在 Partial Synchronous System (半同步系统) 中,一个弱化的 CAP 是能达到的:对全部的数据访问,总返回一个结果 * 若是期间没有报文丢失,那么返回一个知足 consistency 要求的结果。

  这里的半同步系统指每一个节点存在一个时钟,这些时钟不须要同步,可是按照相同的速率流逝。更通俗的来讲,就是一个可以实现超时机制的系统。

  举个例子,系统能够把这个数据只放在一个节点上,其余节点收到请求后向这个节点读或写数据,并设置一个定时器,若是超时前获得结果,那么返回这个结果,不然返回失败。更进一步的,也是最重要的,实现一个知足最终一致性 (Eventually Consistency) 和 AP 的系统是可行的。 现实中的一个例子是 Cassandra 系统。

  而对于分布式数据系统,分区容忍性是基本要求,不然就失去了价值。所以设计分布式数据系统,就是在一致性和可用性之间取一个平衡。对于大多数WEB应用,其实并不须要强一致性,所以牺牲一致性而换取高可用性,是多数分布式数据库产品的方向。 固然,牺牲一致性,并非彻底无论数据的一致性,不然数据是混乱的,那么系统可用性再高分布式再好也没有了价值。牺牲一致性,只是再也不要求关系型数据库中的强一致性,而是只要系统能达到最终一致性便可,考虑到客户体验,这个最终一致的时间窗口,要尽量的对用户透明,也就是须要保障“用户感知到的一致性”。一般是经过数据的多份异步复制来实现系统的高可用和数据的最终一致性的,“用户感知到的一致性”的时间窗口则取决于数据复制到一致状态的时间。

  最终一致性(EVENTUALLY CONSISTENT) 对于一致性,能够分为从客户端和服务端两个不一样的视角。从客户端来看,一致性主要指的是多并发访问时更新过的数据如何获取的问题。从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致。一致性是由于有并发读写才有的问题,所以在理解一致性的问题时,必定要注意结合考虑并发读写的场景。 从客户端角度,多进程并发访问时,更新过的数据在不一样进程如何获取的不一样策略,决定了不一样的一致性。对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。若是能容忍后续的部分或者所有访问不到,则是弱一致性。若是通过一段时间后要求能访问到更新后的数据,则是最终一致性。 最终一致性根据更新数据后各进程访问到数据的时间和方式的不一样,又能够区分为: 因果一致性(CAUSAL CONSISTENCY)

  若是进程A通知进程B它已更新了一个数据项,那么进程B的后续访问将返回更新后的值,且一次写入将保证取代前一次写入。与进程A无因果关系的进程C的访问遵照通常的最终一致性规则。“读己之所写(READ-YOUR-WRITES)”一致性。当进程A本身更新一个数据项以后,它老是访问到更新过的值,毫不会看到旧值。这是因果一致性模型的一个特例。会话(SESSION)一致性。这是上一个模型的实用版本,它把访问存储系统的进程放到会话的上下文中。只要会话还存在,系统就保证“读己之所写”一致性。若是因为某些失败情形令会话终止,就要创建新的会话,并且系统的保证不会延续到新的会话。单调(MONOTONIC)读一致性。若是进程已经看到过数据对象的某个值,那么任何后续访问都不会返回在那个值以前的值。单调写一致性。系统保证来自同一个进程的写操做顺序执行。要是系统不能保证这种程度的一致性,就很是难以编程了。上述最终一致性的不一样方式能够进行组合,例如单调读一致性和读己之所写一致性就能够组合实现。而且从实践的角度来看,这二者的组合,读取本身更新的数据,和一旦读取到最新的版本不会再读取旧版本,对于此架构上的程序开发来讲,会少不少额外的烦恼。 从服务端角度,如何尽快将更新后的数据分布到整个系统,下降达到最终一致性的时间窗口,是提升系统的可用度和用户体验很是重要的方面。

  对于分布式数据系统: N — 数据复制的份数,W — 更新数据是须要保证写完成的节点数,R — 读取数据的时候须要读取的节点数若是W+R>N,写的节点和读的节点重叠,则是强一致性。例如对于典型的一主一备同步复制的关系型数据库,N=2,W=2,R=1,则无论读的是主库仍是备库的数据,都是一致的。 若是W+R<=N,则是弱一致性。例如对于一主一备异步复制的关系型数据库,N=2,W=1,R=1,则若是读的是备库,就可能没法读取主库已经更新过的数据,因此是弱一致性。 对于分布式系统,为了保证高可用性,通常设置N>=3。不一样的N,W,R组合,是在可用性和一致性之间取一个平衡,以适应不一样的应用场景。 若是N=W,R=1,任何一个写节点失效,都会致使写失败,所以可用性会下降,可是因为数据分布的N个节点是同步写入的,所以能够保证强一致性。若是N=R,W=1,只须要一个节点写入成功便可,写性能和可用性都比较高。可是读取其余节点的进程可能不能获取更新后的数据,所以是弱一致性。这种状况下,若是W<(N+1)/2,而且写入的节点不重叠的话,则会存在写冲突。

八.参考文献

  [1]http://www.infoq.com/cn/articles/cap-twelve-years-later-how-the-rules-have-changed/  [2]http://blog.csdn.net/it_man/article/details/8574201  [3]http://www.cnblogs.com/mmjx/archive/2011/12/19/2290540.html  [4]http://blog.csdn.net/zhangzhebjut/article/details/22977977