CAP理论指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
先说结论:
一般是 CP、AP 两种情况。P 可以算是分布式的基础。当然也可以选择 CA,即不允许分区。
分析:
通过一个案例来分析一下
现在网络中某个服务两个节点S1和S2,他们之间网络可以连通,S1中有一个应用程序APP1,和一个数据库DB1,S2也有一个应用程序APP2和一个数据库DB2。现在,APP1和APP2是分布式系统的两个部分,DB1、DB2是分布式系统的两个子数据库。
现在问题来了。突然有两个用户A和B分别同时访问了S1和S2。理想中的操作是下面这样的:
A访问S1节点,B访问S2节点
A通过S1节点,将DB1的数据Num库存减一变成了0
同步操作触发:DB2的数据Num库存同步DB1的操作变成了0
B 读取到的 Num 数据为0
上面这是一种最理想的情景。它满足了CAP理论的三个特性。现在我们看看如何来理解满足的这三个特性。
Consistency 一致性
一致性是指“all nodes see the same data at the same time”,即更新操作成功后,所有节点在同一时间的数据完全一致。就好比刚刚举得例子中,A和B读取的都是正确的数据,对用户来说,就好像是操作了同一个数据库的同一个数据一样。
一致性可以分为客户端和服务端两个不同的视角:
从客户端角度来看,一致性主要指多个用户并发访问时更新的数据如何被其他用户获取的问题;
从服务端来看,一致性则是用户进行数据更新时如何将数据复制到整个系统,以保证数据的一致。
对于一致性,一致的程度不同大体可以分为强、弱、最终一致性三类。
-
强一致性
对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。比如A更新库存从1到0,那么B读取的时候也应该是0,防止超卖。 -
弱一致性
后续的部分用户或者全部用户得到的数据是未更新前的,则是弱一致性。比如A更新库存从1到0,B或者C读取到的是1,像买火车票的时候,多个人同时看到剩余一张票,但是其实已经没票了,通过购买的时候再做防止超卖校验。
- 最终一致性
经过一段时间后能获取到更新后的数据,则是最终一致性。比如A更新库存从1到0,B或者C在一段时间后获取到是库存为0.
可用性
可用性是指“reads and writes always succeed”,即用户访问数据时,系统是否能在正常响应时间返回结果。
好的可用性主要是指系统能够很好地为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。在通常情况下,可用性与分布式数据冗余、负载均衡等有着很大的关联。
分区容错性
分区容错性是指“the system continues to operate despite arbitrary message loss or failure of part of the system”,即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。分区容错可视为在系统中采用多副本策略。
在理想情况下,没有出现任何错误的时候,这三条应该都是满足的。但是天有不测风云。系统总是会出现各种各样的问题。下面来分析一下为什么说CAP理论只能满足两条。
CAP 取舍
想象一下上面的案例中: A 用户更新了 DB1库存 Num 为0,此时 通知DB2更新的时候网络故障或者DB2更新失败。那么 对于B 用户怎么办呢?
可以有两种选择:
牺牲数据一致性,虽然库存已经为0,但是B看到的库存仍为1
牺牲可用性,B想要获取的最新的存款,那就一直等待阻塞,一直到网络故障恢复,DB2更新成功。
现在你可以看到了CAP三个特性不能同时满足的,但是可以满足其中两个。
CA without P
不要求 Partition Tolerance,即不允许分区,则强一致性和可用性是可以保证的。其实分区是始终存在的问题,因此 CA 的分布式系统更多的是允许分区后各子系统依然保持 CA。
CP without A
不要求可用性,每个请求结果都需要在各服务器之间实现强一致性,但是分区容错性会导致同步时间无限延长,如此 CP 也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
AP without C
可用性高并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了实现高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。
在实践中,根据实际情况进行权衡取舍。CAP 理论可用在不同的层面,可以根据 CAP 原理定制局部的设计策略,例如,在分布式系统中,每个节点自身的数据是能保证 CA 的,但在整体上又要兼顾 AP 或 CP。