在单机的数据库系统之中,我们很容易实现一套满足ACID 特性的 事务处理系统, 事务的一致性不存在问题。 但是在分布式系统之中,由于数据分布在不同的主机结点上,如何对着些数据进行分布式的事务处理就具有非常大的挑战,CAP 理论的出现,让我们对于分布式事务的一致性有了另外一种看法。
什么是CAP 理论?在计算机科学理论,CAP 理论 (也称Brewer 定理) 又有称为 CAP原则,CAP定理,是由计算机科学家Eric Brewer 在 2000 年 提出的 ,其理论观点是, 在分布式计算机系统中,不可能存在同时提供 以下全部三个保证。
Consistency(一致性): 所有节点同一时间看到的是相同的数据。在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
Availability(可用性):不管是否成功,确保每一个请求都能接收到响应。在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
Partition tolerance(分区容错性):系统任意分区后,在网络故障时,仍能操作。以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CAP原则是NOSQL数据库和分布式系统的基石。
为什么说CAP 只能三选二?举个栗子:
下图 显示了在一个网络中,N1,N2 是两个节点,他们共享数据块V 其中一个 值V0, 运行在N1 的A 程序可以认为是安全的,无Bug,可预测的和可靠的,运行在N2 的是B 程序,在这个例子中,A 将写入V的新值。而B从V 中读取值。
系统预期执行下面的操作:
写入一个V 的新值 V1 。
然后消息(M) 从N1 更新V 的副本到N2.
从B 处读取返回的V1
如果网络是分区的,当N1到N2 的消息不能传递的时候,就会出现虽然N2 能访问到V 的值(可用性),但是实际上与N1 的V 值已经不一致了。 如下图:
CAP 常见模型:既然 CAP 理论已经证明一致性,可用性和分区容错性三者不可能通知达成。 那么在实际应用中,我们可在其他某一方面来放松条件,从而达到妥协,下面是一些常用的模型。
牺牲分区 (CA 模型)
牺牲分区容错性意味着把所有机器搬到一台机器内部,或者放到一个“要死一起上死”的机架上面(机架也可能出现部分失效),这明显就违背了我们希望的可伸缩性。
常见例子:
单站点数据库
集群数据库
LDAP
xFS 文件系统
实现方式:
两阶段提交, 缓存验证协议。
2. 牺牲可用性(CP 模型)
牺牲可用性意味着一旦系统出现分区这样的错误, 系统就直接停止服务。
常见例子:
分布式数据库
分布式锁定
绝大部分协议
实现方式:
悲观锁, 少数分区不可用。
3 . 牺牲一致性(AP 模型)
常见例子:
Coda
Web缓存
DNS
实现方式:
到期/租赁, 解决冲突, 乐观。
CAP 的意义:在系统架构时,应该是根据具体的业务场景来权衡CAP, 比如 对于大多数互联网应用来说(如门户网站),因为 机器数量庞大,部署结点分散,网络故障是常态的,所以可用性是必须的所以只有舍弃一致性来保证服务的AP 而对于银行等需要确保一致性的场景,通常会权衡CA, 和CP 模型。
CAP 的最新发展:Eric Brewer 在2012 年发表文章指出了CAP里面三选二的做法存在一定的误差性,主要体现在:
由于分区很少发生,那么在系统中不存在分区的情况下,没有什么理由牺牲C或A 。
C与A 之间的取舍可以在同一系统内以非常细小的粒度反复发生,而每一次的决策可能因为具体的操作,乃至因为牵涉特定的数据或用户而有所不同。
这三种性质都可以在一定程度上衡量,并不是非黑即白的有或无。可用性显然是在0% 到100% 之间连续变化的,一致性分很多级别,连分区也可以细分不同的含义,如系统内的不同部分对于是否存在分区可以有不一样的认知。