CAP原则概述
C
=Consistency
=一致性A
=Availability
=可用性P
=Partition tolerance
=分区容错性
1998
年,加州大学的计算机科学家Eric Brewer
提出,分布式系统有三个指标
- 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值,即写操作之后的读操作,必须返回该值。(分为弱一致性、强一致性和最终一致性)
- 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
- 分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
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
。
上面的过程比较简单,但也说明了要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。也就是说分布式系统不可能同时满足三个特性。这就需要我们在搭建系统时进行取舍了,那么,怎么取舍才是更好的策略呢?
BASE理论解决方案
BA
=Basically Available
=基本可用S
=Soft state
=软状态E
=Eventually consistent
=最终一致性
BASE是对CAP中一致性和可用性权衡的结果。
核心思想:即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)
基本可用Basically Available
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性——但请注意,这绝不等价于系统不可用,以下两个就是“基本可用”的典型例子。
- 响应时间上的损失:正常情况下,一个在线搜索引擎需要0.5秒内返回给用户相应的查询结果,但由于出现异常(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了1~2秒。
- 功能上的损失:正常情况下,在一个电子商务网站上进行购物,消费者几乎能够顺利地完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
软状态Soft state
软状态也称弱状态,和硬状态相对,是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
最终一致性Eventually consistent
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
亚马逊首席技术官Werner Vogels在于2008年发表的一篇文章中对最终一致性进行了非常详细的介绍。他认为最终一致性时一种特殊的弱一致性:系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问都能够胡渠道最新的值。同时,在没有发生故障的前提下,数据达到一致状态的时间延迟,取决于网络延迟,系统负载和数据复制方案设计等因素。
在实际工程实践中,最终一致性存在以下五类主要变种。
- 因果一致性
- 因果一致性是指,如果进程A在更新完某个数据项后通知了进程B,那么进程B之后对该数据项的访问都应该能够获取到进程A更新后的最新值,并且如果进程B要对该数据项进行更新操作的话,务必基于进程A更新后的最新值,即不能发生丢失更新情况。与此同时,与进程A无因果关系的进程C的数据访问则没有这样的限制。
- 读己之所写
- 读己之所写是指,进程A更新一个数据项之后,它自己总是能够访问到更新过的最新值,而不会看到旧值。也就是说,对于单个数据获取者而言,其读取到的数据一定不会比自己上次写入的值旧。因此,读己之所写也可以看作是一种特殊的因果一致性。
- 会话一致性
- 会话一致性将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现“读己之所写”的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。
- 单调读一致性
- 单调读一致性是指如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。
- 单调写一致性
- 单调写一致性是指,一个系统需要能够保证来自同一个进程的写操作被顺序地执行。
总的来说,BASE
理论面向的是大型高可用可扩展的分布式系统,和传统事务的ACID
特性是相反的,它完全不同于ACID
的强一致性模型,而是提出通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID
特性与BASE
理论往往又会结合在一起使用。