分布式系统的CAP理论是由Eric Brewer于1999年首先提出的,又被称作布鲁尔定理(Brewer's theorem),CAP是对Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容忍性)的一种简称,如下图所示:
它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
一致性(Consistency):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(Availability):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
容忍网络分区(Partition tolerance):
the system continues to operate despite arbitrary message loss or failure of part of the system,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务
分区容错性和扩展性紧密相关。在分布式应用中,可能因为一些分布式的原因导致系统无法正常运转。好的分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转正常的 整体。比如现在的分布式系统中有某一个或者几个机器宕掉了,其他剩下的机器还能够正常运转满足系统需求,或者是机器之间有网络异常,将分布式系统分隔未独立的几个部分,各个部分还能维持分布式 系统的运作,这样就具有好的分区容错性。
为了进一步理解CAP定理,我们来看一个简单的例子:假定在分布式系统中有两个节点m1和m2,分别存储数据a的副本,作用在m1上的更新操作将数据a从v1更新成v2。该系统具备分区容忍性P,假定现在系统发生了故障,m1和m2之间的网络断开了,考虑以下两种情况:
情况一:若要保证一致性C,则要求数据a的所有副本必须一致,即保证m2上的数据a也被更新为v2而与m1同步。而此时由于发生网络故障,m1与m2无法进行通信,进而无法将数据a同步到一致状态。这样,对于m2上数据a的读请求必然要被拒绝,因此无法保证系统的可用性A。此种情况下,我们选择了CAP中的CP而放弃了A,如下图所示:
系统选择CP的情况
-
情况二:若要保证可用性A,那么对于m2上数据a的读请求必须在限定时间内返回。在网络故障尚未解决之前,m1和m2无法进行通信,此时m2返回的a指为v1,而并非是当前数据a的最新状态v2,即出现了数据的不一致状态,因此无法保证系统的一致性C。此种情况下,我们选择了CAP中的AP而放弃了C,如下图所示:
系统选择AP的情况但是,如果我们的系统是强事务型,即实现了CA,那又是什么情况呢?
-
情况三:如果系统实现的是CA,答案很简单,因为系统放弃了P,所以当网络发生故障时,将数据a从v1更新成v2的操作根本就不会成功(这里回顾一下分区容忍性的概念,当网络发生分区时,系统依然可用,我们这里放弃了P,所以更新操作将不会成功),所以在系统实现CA的情况下,数据a将还是v1,系统依然是一致地、可用的,因为你读操作还能给你正确返回,如下图所示:
系统选择CA的情况
综上可知,对于一个分布式系统来说,C、A、P三者不可兼得。
另一个例子来证明一下,为什么不能同时满足CAP这三个特性?
假设有两台服务器,一台放着应用A和数据库V,一台放着应用B和数据库V,他们之间的网络可以互通,也就相当于分布式系统的两个部分。
在满足一致性的时候,两台服务器 N1和N2,一开始两台服务器的数据是一样的,DB0=DB0。在满足可用性的时候,用户不管是请求N1或者N2,都会得到立即响应。在满足分区容错性的情况下,N1和N2有任何一方宕机,或者网络不通的时候,都不会影响N1和N2彼此之间的正常运作。
当用户通过N1中的A应用请求数据更新到服务器DB0后,这时N1中的服务器DB0变为DB1,通过分布式系统的数据同步更新操作,N2服务器中的数据库V0也更新为了DB1,这时,用户通过B向数据库发起请求得到的数据就是即时更新后的数据DB1。
上面是正常运作的情况,但分布式系统中,最大的问题就是网络传输问题,现在假设一种极端情况,N1和N2之间的网络断开了,但我们仍要支持这种网络异常,也就是满足分区容错性,那么这样能不能同时满足一致性和可用性呢?
假设N1和N2之间通信的时候网络突然出现故障,有用户向N1发送数据更新请求,那N1中的数据DB0将被更新为DB1,由于网络是断开的,N2中的数据库仍旧是DB0;
如果这个时候,有用户向N2发送数据读取请求,由于数据还没有进行同步,应用程序没办法立即给用户返回最新的数据DB1,怎么办呢?有二种选择,第一,牺牲数据一致性,响应旧的数据DB0给用户;第二,牺牲可用性,阻塞等待,直到网络连接恢复,数据更新操作完成之后,再给用户响应最新的数据DB1。
上面的过程比较简单,但也说明了要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。也就是说分布式系统不可能同时满足三个特性。这就需要我们在搭建系统时进行取舍了,那么,怎么取舍才是更好的策略呢?
取舍策略
CAP三个特性只能满足其中两个,那么取舍的策略就共有三种:
CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但放弃P的同时也就意味着放弃了系统的扩展性,也就是分布式节点受限,没办法部署子节点,这是违背分布式系统设计的初衷的。
CP without A:如果不要求A(可用),相当于每个请求都需要在服务器之间保持强一致,而P(分区)会导致同步时间无限延长(也就是等待数据同步完才能正常访问服务),一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。设计成CP的系统其实不少,最典型的就是分布式数据库,如Redis、HBase等。对于这些分布式数据库来说,数据的一致性是最基本的要求,因为如果连这个标准都达不到,那么直接采用关系型数据库就好,没必要再浪费资源来部署分布式数据库。
AP wihtout C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。典型的应用就如某米的抢购手机场景,可能前几秒你浏览商品的时候页面提示是有库存的,当你选择完商品准备下单的时候,系统提示你下单失败,商品已售完。这其实就是先在 A(可用性)方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,虽然多少会影响一些用户体验,但也不至于造成用户购物流程的严重阻塞。
CAP小结:
现如今,对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,节点只会越来越多,所以节点故障、网络故障是常态,因此分区容错性也就成为了一个分布式系统必然要面对的问题。那么就只能在C和A之间进行取舍。但对于传统的项目就可能有所不同,拿银行的转账系统来说,涉及到金钱的对于数据一致性不能做出一丝的让步,C必须保证,出现网络故障的话,宁可停止服务,可以在A和P之间做取舍。
总而言之,没有最好的策略,好的系统应该是根据业务场景来进行架构设计的,只有适合的才是最好的。
BASE理论
对于很多互联网应用来说,对一致性的要求可以降低,而可用性的要求则更为重要,从而产生了弱一致性的BASE理论。BASE理论是基于CAP理论逐步演化而来的,其核心思想是即使不能达到强一致性,也可以根据应用特点采用适当的方法来达到最终一致性的效果。BASE是Basically Available(基本可用)、Soft state(软状态/柔性状态)、Eventually consistent(最终一致性)三个词组的简写,是对CAP中C和A的延伸。
BASE理论的含义如下:
- 基本可用:在绝大多数时间内系统处于可用状态,允许偶尔的失败。
- 软状态/柔性状态:数据状态不要求在任意时刻都完全保持同步,即状态可以有一段时间不同步。
- 最终一致性:与强一致性相比,最终一致性是一种弱一致性。尽管软状态不要求任意时刻数据保持一致同步,但是最终一致性要求在给定时间窗口内数据会达到一致状态。
以上就是BASE理论的基本概念,可见BASE理论强调的是系统的高可用,允许系统在一定时间内存在数据不一致,但在给定的时间窗口内,系统最终一定是要达到一致状态的。
总结及思考
系统从集中式发展到分布式,一部分原因在于单机无法满足日益庞大的数据的存储与处理,而引入分布式后,我们又不得不面对分布式系统中的网络问题。
分布式系统CAP理论及BASE理论可以说是分布式系统设计的基石,这些基本理论对于深入理解分布式环境下技术方案设计选型具有重要的指导作用。而其中BASE理论也可以说是对CAP理论的一种扩展,通过系统的软状态,最终一致性的特点,婉转的实现了CAP三者的结合。