CAP定理(原则)以及BASE理论
CAP定理(原则)概念
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
1. 数据一致性(consistency)
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
2. 服务可用性(availability)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
3. 分区容错性(partition-tolerance)
分区容忍性(P):在网络分区的情况下,被分隔的节点仍能正常对外服务
由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。
以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
一个分布式系统里面,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有些节点之间不连通了,整个网络就分成了几块区域。数据就散布在了这些不连通的区域中。这就叫分区。
当你一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就访问不到这个数据了。这时分区就是无法容忍的。
提高分区容忍性的办法就是一个数据项复制到多个节点上,那么出现分区之后,这一数据项就可能分布到各个区里。容忍性就提高了。然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点上面的数据可能是不一致的。要保证一致,每次写操作就都要等待全部节点写成功,而这等待又会带来可用性的问题。
总的来说就是,数据存在的节点越多,分区容忍性越高,但要复制更新的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据所需要的时间就越长,可用性就会降低。
根据定理,分布式系统只能满足三项中的两项而不可能满足全部三项。
理解CAP理论的最简单方式是想象两个节点分处分区两侧。 允许至少一个节点更新状态会导致数据不一致,即丧失了C性质。 如果为了保证数据一致性,将分区一侧的节点设置为不可用,那么又丧失了A性质。 除非两个节点可以互相通信,才能既保证C又保证A,这又会导致丧失P性质。
CA非0/1的选择
P 是必选项,那3选2的选择题不就变成数据一致性(consistency)、服务可用性(availability) 2选1?工程实践中一致性有不同程度,可用性也有不同等级,在保证分区容错性的前提下,放宽约束后可以兼顾一致性和可用性,两者不是非此即彼。
CAP定理证明中的一致性指强一致性,强一致性要求多节点组成的被调要能像单节点一样运作、操作具备原子性,数据在时间、时序上都有要求。如果放宽这些要求,还有其他一致性类型:
- 序列一致性(sequential consistency):不要求时序一致,A操作先于B操作,在B操作后如果所有调用端读操作得到A操作的结果,满足序列一致性
- 最终一致性(eventual consistency):放宽对时间的要求,在被调完成操作响应后的某个时间点,被调多个节点的数据最终达成一致
可用性在CAP定理里指所有读写操作必须要能终止,实际应用中从主调、被调两个不同的视角,可用性具有不同的含义。当P(网络分区)出现时,主调可以只支持读操作,通过牺牲部分可用性达成数据一致。
工程实践中,较常见的做法是通过异步拷贝副本(asynchronous replication)、quorum/NRW,实现在调用端看来数据强一致、被调端最终一致,在调用端看来服务可用、被调端允许部分节点不可用(或被网络分隔)的效果。
延时(latency),它是衡量系统可用性、与用户体验直接相关的一项重要指标[16]。CAP理论中的可用性要求操作能终止、不无休止地进行,除此之外,我们还关心到底需要多长时间能结束操作,这就是延时,它值得我们设计、实现分布式系统时单列出来考虑。
延时与数据一致性也是一对“冤家”,如果要达到强一致性、多个副本数据一致,必然增加延时。加上延时的考量,我们得到一个CAP理论的修改版本PACELC:如果出现P(网络分区),如何在A(服务可用性)、C(数据一致性)之间选择;否则,如何在L(延时)、C(数据一致性)之间选择。
CAP原理实例推导
以数据库为例,讨论一下CAP原理:
单实例
一种最简单的情况:"单数据库实例"。 这也是最常见的小站点、个人博客、小论坛的架构。
可以很容易分析出来,由于单实例,所以不存在“网络分区”、“不一致”, 但单点故障后会导致整个数据库瘫痪,所以可用性不能保证。
这就是CAP定理中的,保证"C"和"P",舍弃"A"。
所有单机版的系统都属于这个范畴,例如MySQL、memcached、redis。
分片Sharding
为了提升可用性,我们在实际生产环境下经常会在客户端应用一些哈希算法,进行数据分片存放,如下图所示:
由于数据是分片存储在每个数据库中,所以依旧能保证数据一致性。由于数据库之间没有互相通信,并不依赖彼此的存在,所以分区可容忍性依旧没有破坏。那么可用性呢?很多时候会有人直接拍脑袋,这里我们用数学的方式来解答这个问题。
假设,集群有两台服务器,数据分布均匀,我们数据库实例宕机的概率是p。 那么这种利用哈希进行数据分片的集群的可用性为:
0.5*p*(1-p) + 0.5*p*(1-p) + 1*p*p = p
即使,数据分布均匀或者集群数量增大,结果也是一样的:“集群可用性依旧为p”。
那我们折腾了半天,CAP和单机竟然是一样的,这种情况下CAP各项指标虽然没有提升,但好处是:
- 单个服务器宕机只会导致服务降级;
- 集群有了扩容缩容的可能性,这就叫做scalability。
这种分布式的方式常用于:分布式memcached、redis、传统的数据库Sharding、BigTable (列存储式数据库)、Hypertable (列存储式数据库)、HBase (列存储式数据库)、MongoDB (文档式数据库)、Terrastore (文档式数据库)、Redis (KV数据库)、Scalaris (KV数据库)、MemcacheDB (KV数据库)、Berkeley DB (KV数据库)
多副本写入
Client多副本写入,就是Client在写数据库的时候对多个数据库进行写入,并且在两个都写入成功后才认为成功。 由于数据存在多个副本,这种方式会大大的提高读取的可用性。但由于写入的时候要多写, 副本所在的所有实例都必须可用才能成功。所以写入的可用性反而下降了。
假设单机数据库的故障率为p(p<1.0),那么单机数据库的可用性为1-p。 总结就是:
- 在写入的场景下,一致性( C )和分区可容忍性( P )没有变化,可用性( A )反而有所下降, 从1-p降低到1-2p-p2
- 在读取的场景下,一致性( C )和分区可容忍性( P )依旧没有变化,可用性( A )有所上升, 从1-p上升到1-p2
"Client多副本写入"这种写入方式非常适合于在"读多写少"的场景下提高可用性。
为了改善写入时糟糕的可用性,这种方式还有一些“变种”,例如:
- 写成功部分副本就返回成功,剩下的副本写入不保证结果。这样做的结果就是牺牲一定的一致性( C ),换取可用性( A )的提升。
总的来说,这种方式属于广义的"Sharding"的范畴,除去上述的缺点还有一个较大的问题就是:
- 假设副本数为n,Client写入单实例的耗时为t,多副本写入的耗时就是n*t;当n > 1的时候会成倍的影响Client的写入性能。
集群Clustering
为了解决Client写入慢调用复杂等问题,我们引入了集群方案,也就是Clustering。 Clustering和Sharding对比如下:
多副本模式1:
我们可以看到,由于多个副本写入成功才返回,这种方式一致性( C )依旧是保证的。 但写入可用性( A )和分区可容忍性( P )相对于单机均会下降。换来的是:
- 较为简单的API,客户端不用关注“多写”问题;
- 读取操作的高可用(HA)。
由于上述方案是强一致性( C )的,这种应用场景常见于金融系统,这种这方面典型的代表有:ZooKeeper (KV数据库)、Vertica (列存储式数据库)、Aster Data (关系型数据库)、Greenplum (关系型数据库)
多副本模式2:
类似"Sharding"中我们采用的方案,生产环境线上的数据库也往往采用放弃一定的一致性( C ) ,来提高可用性( A )和分区可容忍性( P )。
可以看到,由于大多数互联网公司的需求不是要求强一致性( C ), 所以通过放弃一致性,达到更高的可用性( A )和分区可容忍性 ( P )成了目前市面上大多数NoSQL数据库的核心思想。
在Amazon著名的分布式数据库Dynamo中,就是采用类似的方法:"3副本,写入2个成功后就返回成功,剩下的1个副本后续再进行同步",我们称这种模式叫"最终一致性"。
这方面典型的代表还有:Dynamo (KV数据库)、Voldemort (KV数据库)、Tokyo Cabinet (KV数据库)、KAI (KV数据库)、Cassandra (列存储式数据库)、CouchDB (文档式数据库)、SimpleDB (文档式数据库)、Riak (文档式数据库)、MooseFS (类GFS分布式文件系统)
我们可以看到,系统设计就像穷人家的被子,盖住头和左脚就露出右脚,盖住头和右脚就露出左脚…… 即使你再有钱也不可能将CAP同时100%满足。
我们可以通过用更高可靠性的服务器、更可靠的网络设备达到CAP同时提升。
BASE理论概念
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写,BASE是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
Basically Availble --基本可用
支持分区失败(Sharding碎片划分数据库),出了问题服务仅降级(部分不可用)。
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性——但请注意,这绝不等价于系统不可用,以下两个就是“基本可用”的典型例子:
- 响应时间上的损失:正常情况下,一个在线搜索引擎需要0.5秒内返回给用户相应的查询结果,但由于出现异常(比如系统部分机房发生断电或断网故障),查询结果的响应时间增加到了1~2秒。
- 功能上的损失:正常情况下,在一个电子商务网站上进行购物,消费者几乎能够顺利地完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面。
Soft-state --软状态/柔性
事务"Soft state" 可以理解为"无连接"的, 而 "Hard state" 是"面向连接"的。软状态就是可以有一段时间不同步,异步。
软状态,指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
Eventual Consistency --最终一致性
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
亚马逊首席技术官Werner Vogels在于2008年发表的一篇文章中对最终一致性进行了非常详细的介绍。他认为最终一致性时一种特殊的弱一致性:系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问都能够获取到最新的值。同时,在没有发生故障的前提下,数据达到一致状态的时间延迟取决于网络延迟,系统负载和数据复制方案设计等因素。
http://www.frankyang.cn/2017/09/05/cap-base/