CAP

定义

C,Consistency,“all nodes see the same data at the same time”,即更新操作成功并返回客户端之后,所有节点在同一时间的数据完全一致。即所有节点拥有数据的最新版本。

A,Availability,可用性:“Reads and writes always succed”,即服务一直可用,而且是正常响应时间。

对于一个可用性的分布式系统,每个非故障节点必须对每一个请求做出响应。即,该系统使用的任何算法必须最终终止。当同事要求分区容忍性时,这是一个很强的定义:即使是严重的网络错误,每个请求也必须能够终止。

P,Partition Tolerance,分区容忍性:“the system continues to operate despite arbitrary message loss or failure of part of the system”,即系统容忍网络出现分区、分区之间网络不可达的情况。分区容忍性和可扩展性紧密相关。整体来说指的是,在遇到特定节点或网络分区故障时,仍然能够对外提供满足一致性和可用性的服务。

P,分区容忍性

什么是分区容忍性:

  • 一个分布式系统中,节点组成的网络本来应该是连通的。然而可能因为一些故障,使得有的节点之间不再连通,整个网络就分成了几块区域。数据就散步在这些不连通的区域中,就成为分区现象
  • 当一个数据项只在一个节点中保存,那么分区出现后,和这个节点不连通的部分就无法访问到该数据项。这时分区是无法容忍的
  • 提高分区容忍性的办法就是将一个数据项复制到多个节点上,那么在出现分区之后,这一数据项就可能分布在各个区域中,容忍性就提高了
  • 然而,要把数据复制到多个节点,就会带来一致性的问题,就是多个节点之上的数据可能是不一致的。
  • 要保证一致,每次写操作就要等待所有节点写成功,则这种等待又会带来可用性问题。
  • 总的来说就是,数据存在的节点越多,分区容忍性就越高,但是要复制的数据就越多,一致性就越难保证。为了保证一致性,更新所有节点数据的操作就会耗时更长,导致可用性降低。

不能同时满足的证明

假设系统中有 5 个节点,N1~N5,N1/N2/N3 在物理机房 A,N4/N5 在物理机房 B。现在发生了网络分区,机房 A 和机房 B 之间的网络不互通。

保证一致性:此时客户端在 A 机房写入数据,不能同步到 B 机房。写入失败。此时失去了可用性。

保证可用性:数据在 A 机房的 N1~N3 节点都写入成功并返回完成。数据在 B 机房的 N4~N5 节点也写入数据成功并返回完成。同一份数据在 A 和 B 机房出现了不一致的情况。

比如想象 ZK,当一个节点宕机,系统将其踢出集群,然后其他一般以上的节点写入成功即可。是不是 ZK 就满足了 CAP 呢。其实这里有一个误区,系统将其踢出集群,有一个隐含条件,系统引入了一个调度者——一个踢出失败节点的调度者。如果调度者和 ZK 节点出现网络分区时,整个系统是不可用的。

常见场景

在网络分区无法避免的情况下,一致性和可用性必须二选一。而在没有发生网络故障时,即分布式系统正常运行时,一致性和可用性是可以被同时满足的。但是,对于大多数互联网应用来说,因为规模比较大,部署节点分散,网络故障是常态,可用性是必须要保证的,所有只有舍弃一致性来保证服务的 AP。但是对于一些金融相关的行业来说,有很多场景需要保证一致性,这种情况下通常会考虑 CA 和 CP 模型,CA 模型在网络故障时完全不可用,CP 模型具备部分可用性。

CA without P:关注一致性和可用性,需要非常严格的全体一致性协议,比如“2PC”。 CA 系统不能容忍网络错误或节点错误,一旦出现这样的问题,整个系统就会拒绝写请求,因为它并不知道对面的那个节点是否挂掉了,还是只是网络问题。唯一安全的方式就是把自己设置为只读

CP without A:关注一致性和分区容忍性。关注的是系统中大多数节点的一致性协议,比如 Paxos 算法。这样的系统只需要保证大多数节点数据一致,而少数节点会在没有同步到最新数据版本时变为不可用状态,从而提供部分可用性

AP without C:关注可用性和分区容忍性。因此,这样的系统不能达成一致性,需要给出数据冲突,给出数据冲突就需要维护数据版本。Dynamo 就是这样的系统。

对于分布式系统分区容忍性是天然具备的要求,否则一旦出现网络分区,系统就拒绝所有写入只允许可读,这对大部分的场景是不可接收的,因此,在设计分布式系统时,更多的情况下是选举 CP 还是 AP,要么选择强一致性弱可用性,要么选择高可用性容忍弱一致性。