ITPub博客

首页 > 数据库 > 数据库开发技术 > 谈谈CAP

谈谈CAP

原创 数据库开发技术 作者:安瑞哥是码农 时间:2022-02-19 22:36:22 0 删除 编辑

1. 前言

先来回顾下历史,CAP这个理论最初是在2000年时候,由加州大学伯克利分校计算机学院一个名叫埃里克·布鲁尔的博士在一个学术论坛中提出来的一个假设。两年后,由麻省理工学院的赛斯·吉尔伯特和南希·林奇在其论文中证明了这一概念,CAP理论先后经历了2个版本的更迭,最终确定成为分布式领域的一个定理。
CAP是大数据技术中一个绕不开的话题,也是考验一个技术人对一个分布式系统的熟悉程、水平高低的分水岭,这是一个貌似简单,但要说清楚却没那么容易的技术点。
看了很多关于CAP的文章和讨论,感觉都不尽如人意,遂本文将根据这些年来对分布式系统的使用经验来聊聊自己的一些看法。

2. 什么是CAP

这里不想赘述相关的概念,只根据我的理解和总结来进行阐述:

C(consistency):强一致性,也叫线性一致性,指任何时候访问系统时,对于同一份数据,要么都查不到,要么都查能到,如果有多个节点的话,每个节点中的数据都是一模一样的;

A(Availability):高可用,本质就是数据冗余,一份一模一样的数据,在所有节点中都存一份拷贝,如果出现节点故障,只要有另外一个节点可以提供服务,该数据就可以被访问到;

P(Partition-tolerance):分区可扩展/容错:一份数据可以保存到多台机器上,且当出现数据节点彼此间网络不通的情况下,系统依然可以使用;

根据CAP理论,以上3种属性,在任何分布式系统中,都最多只能同时满足其中的2个。

3. 常见误区

这里需要澄清的几个常见理解误区:

  1. 1,CAP理论针对的是系统的数据,即数据节点,而非整个系统本身;
  2. 2,分布式系统在设计时,虽然说只能满足其中的2个,但并不是说另外一个就一定不允许存在;
  3. 3,有些分布式系统的CAP属性会随着系统配置的不同而动态变化,并非一成不变的;

解释一下:

第1点:

比如只有一个master和若干个slaver的分布式系统来说。如HDFS,从集群架构上来看,只有一个namenode和若干个DataNode,namenode是存在单点故障的,而并非高可用。

但是这里我们谈论的CAP针对的是slaver节点中的数据,只要其数据有备份(默认3份),那么该系统就符合高可用的特点,跟master没有关系,这一点要切记,不要混淆;

第2点:

对于一个分布式系统来说,CAP只能同时满足2个指的是在【苛刻】条件下的要求,而非【苛刻】条件下,其实是3个都是可以满足的。

拿Elasticsearch这个分布式存储来说,它在设计时遵循CAP中的AP。

首先满足P,这一点毋庸置疑(几乎所有分布式存储系统都首要考虑P,一份数据可以写到多个节点中,且如果系统出现网络分区导致无法通信,系统一样可以向外提供服务);

其次满足A,因为系统存在备份(可以设置多个冗余分片),且都能同时对外提供读取服务器;

最后再来看C,为什么不满足,原因在于系统的数据都是先全部写到主分片,写完后再把数据同步到冗余分片中,这一过程存在时间差,且在这个过程中所有的数据分片都是可以对外提供服务的,因此无法满足强一致性,即同一时刻对不同数据分片请求数据,获取到的结果会出现不一致。

但是,当主分片的数据全部同步到冗余分片中之后,是不是就一致了呢。因此,这个C最终是满足的,所以Elasticsearch在非【苛刻】条件是可以同时满足CAP的。

第3点:

对于很多分布式系统来说,通过修改一些系统参数是可以在C、A、P之间做动态取舍的。

以HDFS为例,它原本是一个遵循AP的分布式系统,但是我们可以通过控制参数dfs.replication.min来改变这一事实。

dfs.replication.min参数用来控制客户端的最小写入副本数,默认为1。也就是默认情况下,客户端在数据写入时,只要保证其中一个DataNode写入成功,就算成功,后续的数据复制属于异步进行,默认保证AP。

比如HDFS默认的复制因子为3,默认情况下当客户端写入数据到其中一个datanode成功后,客户端即刻返回,剩下的2份数据会由系统的后台线程将其复制到另外2个DataNode中,这里是舍弃了C特性的。

但是如果我现在将dfs.replication.min改为3,那么客户端会一直等待3个DataNode都将这份数据写入成功后才返回,在这个过程中,该份数据是不会对外服务的(即不会commit),这个时候就保证了C特性,而放弃了P,因为这个过程中如果某个DataNode出现网络分区(无法通信),系统会触发选择新DataNode的机制,进而来确保网络分区问题快速解决,否则写入的这份数据是没法commit的,也就不能对外提供服务。

在大家接触的大多数分布式系统中,设计之初都默认会确保P,然后再在C和A之间做取舍,但是有一个系统比较例外,那就是kafka。

kafka不保证P?纳尼?

先来看看kafka的设计者Jun Rao怎么说的。

All distributed systems must make trade-offs between guaranteeing consistency, availability, and partition tolerance. Our goal was to support replication in a Kafka cluster within a single datacenter, where network partitioning is rare, so our design focuses on maintaining highly available and strongly consistent replicas.”

看到没,kafka的设计注重的是A和C属性,抛弃了P,可能会颠覆很多人的一般性认知。

虽然kafka在设计时没有考虑优先保证P,但是并不代表kafka的P属性不存在。

解读:

kafka跟其他分布式系统的特殊之处在于,整个集群架构设计中没有master和slaver之分,但是在其数据存储内部,每个topic中的每个partition却分为leader和follower,和写每个partition的leader和follower构成了一个小系统也就是上面提到的datacenter,所以在kafka内部,存在无数个这样的datacenter。

按照kafka设计者的意图,当数据写入partition中的leader和所有follower之后,客户端才返回,数据才提供服务(即ack=-1的情况),这个时候只要系统设置的冗余因子大于1个,像上文中举的HDFS例子一样,满足了CA,舍弃了P的考虑,一但出现网络分区(datacenter间无法通信),系统就会触发补救机制,来确保网络分区问题很快解决,否则数据不能commit,也就不能对外提供服务。

4. 总结

当你深入去探究CAP的奥秘时,你会发现其实它们之间的区别非常的细微,很容易搞混淆,也特别容易引起争论。这里,我总结出一个判断CAP的规律,让你可以很快判断一个分布式系统到底符合CAP的哪几个。
  1. 对于C:任何时候,当一个客户端去访问系统时候,永远不存在数据不一致的情况,要么找不到,找到就一模一样;

  2. 对于A:任何时候,都不存在单点故障,如果有一个数据节点无法提供服务(出现故障),必然存在至少一个它的备份可以提供一样的服务,且这个切换不需要系统做出额外的动作(如热切换);

  3. 对于P:这个比较难理解一点。任何时候,当系统出现网络分区(可能是任何故障),导致节点彼此无法通信时,但是不影响客户端仍然可以访问系统,只是不能保证访问到你需要的目标数据,且这期间系统不会做出额外的动作来保证这一点;

还是拿刚才举例过的HDFS、ELasticsearch和kafka来论证一下:

对于HDFS来说,默认情况下(不修改系统参数),满足A和P(数据在同步过程中不满足C),好理解;
对于Elasticsearch来说,默认情况下(不修改系统参数),也满足A和P(数据在同步过程中不满足C),好理解;
对于kafka来说,满足AC(ack=-1时),之所以不满足P,原因在于当出现网络分区后,系统会额外采取措施将失联的follower剔除,选出新的follower,而如果leader失联,也会选出新的leader,来确保网络分区这个问题得以修复,否则当前的数据就不能对外提供服务,所以不满足P,可能稍微有点难理解。


综上,用一个准则来判断一个分布式系统是否满足CAP的某个属性就是:任何时候,系统在不需要额外动作的情况下,依然可以正常对外提供服务。


原文作者:安瑞哥是码农;如有侵权,请联系管理员删除。

上一篇: 再谈BASE
请登录后发表评论 登录
全部评论

注册时间:2022-02-16

  • 博文量
    228
  • 访问量
    115420