分布式系统下的CAP定理

本文参考EricBrewer博客加上自己的理解整理。

CAP定理又被成为布鲁尔定理,是加州大学计算机科学家埃里克·布鲁尔提出来的猜想,后来被证明成为分布式计算领域公认的定理。

CAP定义,在高并发的场景下要做取舍,在大型集群中分区容错很难保证,一旦要确保容错性,那么就会损失数据一致性和高可用特性。所以可以认为CAP 的 P 总是成立,剩下的 C 和 A 无法同时做到

1 CAP理解

C 一致性(Consistency)

系统由G1,G2两台服务器组成,两台服务器都有一个数据 V,初始值为V0。G1和G2相互可以通信,也可以与客户端通信。如下图

客户端向G1写入数据,将G1中的V值改成V1,并从G1中读取V的值。目前操作是具备一致的的。如下图

那么此时如果向G2发起读请求的话,因为数据没有同步,就会得到V的值为V0,实际已经向集群写入了V=V1,此时数据不一致。如下图

我们可以通过G1将数据同步到G2,这时客户端再去读取,就会解决一致性的问题。如下图

小结
一致性是指分布式系统中,数据在多节点存在副本,数据如果一直不修改,在读的时候是不存在问题的,访问哪个节点的数据都一样。可一旦要是发生了修改,如果数据同步无法在修改的瞬间广播到所有副本节点那么在读的时候就可能发生数据脏读

A 可用性(Availability)

指的是服务是否可用,范围涵盖终端客户访问我们的系统或者是集群内部相互通讯交换数据,也就是说在Client向Server发起请求时,服务器返回了正确的响应,称之为可用,反之为不可用。
这里有一个问题,如果发送请求在很久之后才返回数据,那么算不算可用?
所以要提出访问延迟的概念,在某个时间范围内响应才算可用。
1s法则
1S法则是面向WEB端,H5链路上加载性能 和体验方向上的一个指标,具体指:

  • “强网” (4G/WIFI)下,1秒完全完成页面加载,包括首屏资源,可看亦可用;
  • 3G下1秒完成首包的返回 ;
  • 2G下1秒完成建连。

P 分区容错性(Partition tolerance)

指发生在分布式系统内部相互访问的通信网络不可以用,但系统依然正常对外提供服务。如下图

上图说明
集群中存在3台节点:server1、server2、server3 。集群内部server1和server3网络不可用,但是server1和server2,server2和server3相互通信是正常的。客户端client1可以与server1和server2通信,客户端client2可以与server2和server3通信。整个集群对于客户端来说不会因为server1和server3之前网络不可用而停止服务。因此我们可以认为集群分区具备容错性。
小结
分区容错性是指分区具有容错性,我们可以尽可能的提高容错性,但是无法避免,如果发生失败,就要在A和C之间做出选择。要么停止系统进行错误恢复,要么继续服务但是降低一致性,所以我们只能保证AP或CP。

2 BASE理论

eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论,BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(StrongConsistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。

基本可用(Basically Available)

在分布式系统出现故障的时候,允许损失部分可用性,支持分区失败,即保证核心可用。

软状态(Soft State)

接受一段时间的状态不同步,及中间状态,而改中间状态不影响系统整体可用性。这里的中间状态就是CAP理论中的数据不一致性。

最终一致性(Eventually Consistent)

上面说软状态,然后不可能一直是软状态,必须有个时间期限。在期限过后系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问最终都能够获取到最新的值。

3 基于CAP架构选型对比

Zookeeper集群

保证CP。即任何时刻对zookeeper的访问请求能得到一致性的数据结果,同时系统对网络分割具备容错性,但是它不能保证每次服务的可用性。从实际情况来分析,在使用zookeeper获取服务列表时,如果zk正在选举或者zk集群中半数以上的机器不可用,那么将无法获取数据。所以说,zk不能保证服务可用性。

Redis集群

保证AP。Redis通过AOF和RDB将数据同步到子节点。如果Master节点挂了,可以很迅速的将Slave提升为Master,尽可能的保证了系统的可用性,但是可能存在数据丢失的问题。所以Redis其实并不适合做分布式锁。

Eureka集群

保证AP,eureka在设计时优先保证可用性,每一个节点都是平等的,一部分节点挂掉不会影响到正常节点的工作,不会出现类似zk的选举leader的过程,客户端发现向某个节点注册或连接失败,会自动切换到其他的节点,只要有一台eureka存在,就可以保证整个服务处在可用状态,只不过有可能这个服务上的信息并不是最新的信息。