分布式 CAP 定理的前世今生

2022-06-19 14:53:17 浏览数 (1)

文章目录

  • 1.CAP 的历史
  • 2.CAP 被上升为定理
  • 3.前所未有的质疑
    • 3.1 质疑 1:概念混乱,废话一堆,不能作为定理
    • 3.2 质疑 2:不适用于数据库事务架构
    • 3.3 质疑 3:应该构建不可变模型避免 CAP 的复杂性
    • 3.4 质疑 4:分区容错概念有误导
  • 4.对质疑的回应
  • 5.如何看待CAP?
  • 参考文献

CAP 理论在互联网界有着广泛的知名度,知识稍微宽泛一点的工程师都会把其作为衡量系统设计的准则。大家都非常清楚地理解了 CAP 定理:任何分布式系统在一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三个方面不能兼得,最多只能得其二。因此,任何分布式系统的设计只是在三者中的不同取舍而已。 事实上,让人吃惊的是 CAP 在国外的影响力完全不如所想,相反还伴随着诸多的争论。下面我们系统地阐述一下 CAP 的来龙去脉。

1.CAP 的历史

1985 年,三位学者 Fischer、Lynch 和 Paterson 共同证明了异步通信中不存在任何一致性的分布式算法,该结论被称之为 FLP Impossibility(FLP 是三位作者名字的首字母缩写)。基于此,人们开始寻找分布式系统设计的各种因素。一致性算法既然不存在,但若能找到一些设计因素,并进行适当的取舍以最大限度满足系统需求成为当时的重要议题。比如,在 CAP 之前研究者就已经发现低延迟和顺序一致性不可能同时被满足。

2000 年,Eric Brewer 教授在分布式计算原理研讨会(PODC)的研讨会上提出了一个猜想:一致性、可用性和分区容错性三者无法在分布式系统中被同时满足,并且最多只能满足其中两个!

这个猜想首次把一致性、可用性和分区容错三个因素提炼出来作为系统设计的重要特征,断言用此三者可以划分所有的分布式系统,并指明这三个特征之间的不可能性关系。Brewer 猜想比单纯的“低延迟和顺序一致性不能被同时满足”的结论更具体,对实际系统的构建也更具可操作性。

Brewer 教授当时想象的分布式场景是 webservice,一组 websevrice 后台运行着众多的 server,对 service 的读写会反应到后台的 server 集群,并对 CAP 进行了定义:

  • C(Consistency:一致性):所有的节点上的数据时刻保持同步。

这里的一致性指的是强一致性,也就是数据更新完,访问任何节点看到的数据完全一致,要和弱一致性,最终一致性区分开来。

  • A(Availability:可用性):每个请求都能接收到一个响应,无论响应成功或失败

这里的可用行还包括不能出现延迟,比如如果节点B由于等待数据同步而阻塞请求,那么节点B就不满足高可用性。也就是说,任何没有发生故障的服务必须在有限的时间内返回合理的结果集。

  • P(Partiton tolerence:分区容错):系统应该能持续提供服务,即使系统内部有消息丢失(分区)

这里的分区是指网络意义上的分区。由于网络是不可靠的,所有节点之间很可能出现无法通讯的情况,在节点不能通信时,要保证系统可以继续正常服务

高可用、数据一致是很多系统设计的目标,但是分区又是不可避免的事情:

  • CA without P:如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此CA的系统更多的是允许分区后各子系统依然保持CA。
  • CP without A:如果不要求A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
  • AP wihtout C:要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。

CAP 的出现仿佛是一盏明灯,它揭露了分布式系统的本质,并给出了设计的准则,而这正是1985年以来人们正在寻找的东西。所以 CAP 在当时的影响力是非常大的!

2.CAP 被上升为定理

2002 年,Lynch 与其他人证明了 Brewer 猜想,从而把 CAP 上升为一个定理。但是,她只是证明了 CAP 三者不可能同时满足,并没有证明任意二者都可满足,所以,该证明被认为是一个收窄的结果。

Lynch 的证明相对比较简单:采用反正法,如果三者可同时满足,则因为允许 P 的存在,一定存在 Server 之间的丢包,如此则不能保证 C,证明简洁而严谨。

在该证明中,对 CAP 的定义进行了更明确的声明:

  • C:一致性被称为原子对象,任何的读写都应该看起来是“原子“的,或串行的。写后面的读一定能读到前面写的内容。所有的读写请求都好像被全局排序
  • A:对任何非失败节点都应该在有限时间内给出请求的回应。(请求的可终止性)
  • P:允许节点之间丢失任意多的消息,当网络分区发生时,节点之间的消息可能会完全丢失

该定义比 Brewer 提出的概念清晰了很多,也显得更加正式化!

3.前所未有的质疑

当国内工程师对 CAP 痴迷的时候,国外的工程师和研究者对 CAP 提出了各种质疑,纷纷有用反例证明着 CAP 在各种场合不适用性,同时挑战着 Lynch 的证明结果!

纵观这些质疑,基本都是拿着一个非常具体的系统,用CAP的理论去套,最后发现要么CAP不能Cover所有的场景,要么是CAP的定义非常模糊,导致自相矛盾!一句话,把 CAP 接地气是非常困难的!

你是否看了 CAP 的概念定义后还是感觉很模糊?如果是,你并不孤独,有很多人都是如此!

CAP 没有考虑不同的基础架构、不同的应用场景、不同的网络基础和用户需求,而 C、A、P 在这些不同场景中的含义可能完全不同,这种无视差异化的定义导致了非常大的概念模糊,同时也变成 CAP 被质疑的源头!

3.1 质疑 1:概念混乱,废话一堆,不能作为定理

在论文 Deconstructing the `CAP theorem’ for CM and DevOps 中,作者对 CAP 发起了强烈的挑战,强烈谴责了 CAP 模糊不一致的概念:

  • 在 CA 中的 C 代表的是本地一致性;CP 中的 C 代表的是全局一致性,AP 中直接没有 C;这些 C 的含义在不同的场景根本就不同。终端- - 用户 agent 该不该引入到 CAP 中?CAP 到底是说一个 agent 的多次更新,还是多个用户的一次更新?没有 agent 参与的系统谈什么一致性?
  • 如果分区发生在系统内部(水平分区),对 agent 而已并没有影响;若分区发生在 agent 与系统间(垂直分区),这种情况对 DNS 系统架构的可用性根本没有任何影响;但对银行事务架构却有巨大影响。也就是说,可用性、分区容错,是两个相关切无法独立切分的概念。

一句话:CAP 说了一些永远不存在的废话!作为一个严格的数学定理,一定要概念清晰并且可自证明,CAP 显然不具备这个条件,并声称“绝不承认其为一个定理”!

论文作者对相对论有相当的理解,从相对论来看,每个节点都只知道自己的结果,永远无法得知其他节点的情况,系统整体是否一致我怎么会知道?

并且作者对一致性、可用性归结为一个非常深刻的见解:一切都是时间视图!多长时间返回结果算可用?多长时间返回认为不可用?多长时间数据同步算一致?因此,一切的本质是时间!

根据时间特性和相对论,作者提出了一个独创的 promise 系统模型,每个节点都对自己的行为在有限时间内进行承诺,其他节点根据这个承诺和自己的状态决定本地如何处理。

作者还上传了自己的笔记拍照,我大体看了下,基本上是构建了一个基于时间同步的有限状态机。实际上 Lynch 早就证明,在同步环境下一致性是可以达到的!

3.2 质疑 2:不适用于数据库事务架构

Errors in Database Systems, Eventual Consistency, and the CAP Theorem 的作者,详细地列举了分布式事务中可能的分区情况,比如说应用因为更新一些错误的数据而导致失败,此时无论使用什么样的高可用方案都是徒劳,因为数据发生了无法修正地错误!作者还列举了其他一些情况,虽然分区发生但无法保持高可用,这就说明了CAP并不能用来完全解释数据库事务架构。

作者还建议,应该放弃分区容错,因为在局域网中分区很少发生;而在广域网中,有各种备选方案,导致实际上的分区也较少发生。

3.3 质疑 3:应该构建不可变模型避免 CAP 的复杂性

How to beat the CAP theorem 一文的标题就是锤死 CAP,可见作者对 CAP 的不屑溢于言表!

作者认为 CAP 的困境在于允许数据变更,每次变更就得数据同步,保持一致性,这样系统非常复杂。

他认为数据就是客观存在的,不可变,只能增、查。传统的 CURD 变为 CR。这个概念非常类似 Cassandra 中的顺序写的概念,任何的变更都是增加记录。通过对所有记录的操作进行合并,从而得到最终记录。

因此,作者认为任何的数据模型都应该抽象为:Query=Function(all data),任何的数据试图都是查询,查询是对全体数据施加了某个函数的结果。这个定义清晰简单,完全抛弃了 CAP 那些繁琐而又模糊的语义。因为每次操作都是对所有数据进行全局计算,也就没有了一致性问题!

有这样的系统吗?有,Hadoop 便是!作者认为,Hadoop 的 HDFS 只支持数据增加,而 Mapeduce 却进行全局计算,完美地符合了他对数据处理的期望!

Hadoop 也存在某个节点数据丢失的问题,但随着流式计算,丢失的数据终究会随着系统的正常而被最终合并,因此数据最终是一致的。

Hadoop 不能进行实时计算咋办?作者又构建了一套基于 Cassandra 和 ElephantDB 的实时数据处理系统。搞得无比复杂!

3.4 质疑 4:分区容错概念有误导

cap-confusion-problems-with-partition-tolerance 一文的作者质疑了 Errors in Database Systems, Eventual Consistency, and the CAP Theorem 作者的观点,但是比较清晰地揭露了 CAP 概念之间的模糊。

作者认为可用性和一致性是分布式系统的属性,而分区却是网络的一个属性。不能在问题发生时是否选择要不要分区,而是应该在分区既定的情况下选择要一致性还是可用性。网络分区会发生在两种情况:

  • 交换机失败,导致网络发生 Errors in Database Systems, Eventual Consistency, and the CAP Theorem 文中描述的情况,网络被分成几个子网
  • 机器延迟或死机,导致某些 server 失去联系

Errors in Database Systems, Eventual Consistency, and the CAP Theorem 文中所谓的分区就是情况 1,每个独立的子网还能正常运作,作者认为这种分区条件非常苛刻,更倾向于认为这只是分区可用性的一种度量方式(发给每个子网的请求都有正确的 Response)。

而实际上,因为机器原因发生的分区情况更常见一些,如果“很多”机器都发生故障,系统会因为一个“多数派”的丢失而导致不可用(比如,因为多数不存在,最新的读可能无法读取到上一次的写)。一句话:分区也同时蕴涵着不可用,这两个概念之间存在重叠。

作者认为,CAP 比较合理的表达方式应该是:在一个允许网络发生故障的系统中,该选择一致性还是可用性?

当系统的机器数量持续增加时,一致性会加剧时延,维护一致性的成本会非常之高,因此我们基本就剩下一种选择:在允许网络失败的系统中,更多地是选择可用性。而 Zookeeper、Hadoop 之所以选择一致性,是因为这些系统多数是由在同一集群的少数节点构成!

作者其实间接地否认了“3个中同时满足2个”这样的误解,而是从更深层次探讨了 CAP 的本质,但并没有试图推翻 CAP。

4.对质疑的回应

面对大量的质疑,Brewer和Lynch终于坐不住了,因此两人纷纷出来澄清:

Brewer 于 2012 年重申:

  • “3 个中的 2 个”这个表述是不准确的,在某些分区极少发生的情况下,三者能顺畅地在一起配合
  • CAP 不仅仅是发生在整个系统中,可能是发生在某个子系统或系统的某个阶段

该声明并不否认像质疑 3 那种三个因素协同工作的情况,并把 CAP 应用在一些更细粒度的场景中。

Lynch 也在 10 年后的 2012 年重写了一篇关于 CAP 的论文 Perspectives on the CAP Theorem,该论文主要做了几件事:

  • 把 CAP 理论的证明局限在原子读写的场景,并申明不支持数据库事务之类的场景
  • 一致性场景不会引入用户 agent,只是发生在后台集群之内
  • 把分区容错归结为一个对网络环境的陈述,而非之前一个独立条件。这实际上就是更加明确了概念
  • 引入了活性(liveness)和安全属性(safety),在一个更抽象的概念下研究分布式系统,并认为 CAP 是活性与安全属性之间权衡的一个特例。其中的一致性属于 liveness,可用性属于 safety。
  • 把 CAP 的研究推到一个更广阔的空间:网络存在同步、部分同步;一致性性的结果也从仅存在一个到存在 N 个(部分一致);引入了通信周期 round,并引用了其他论文,给出了为了保证 N 个一致性结果,至少需要通信的 round 数。也介绍了其他人的一些成果,这些成果分别都对 CAP 的某一个方面做出了特殊的贡献!

其实 Lynch 的论文主要就是两件事:缩小 CAP 适用的定义,消除质疑的场景;展示了 CAP 在非单一一致性结果下的广阔的研究结果!并顺便暗示 CAP 定理依旧正确!

从此论文还是可以看出,Lynch 的功力高出其他质疑者好多!

5.如何看待CAP?

首先肯定的是,CAP 并不适合再作为一个适应任何场景的定理,它的正确性更加适合基于原子读写的 NoSQL 场景。质疑虽然很多,但很多质疑者只是偷换概念,并没有解决各个因素之间的取舍问题。而无论如何,C、A、P 这个三个概念始终存在任何分布式系统,只是不同的模型会对其有不同的呈现,可能某些场景对三者之间的关系敏感,而另一些不敏感。在所有的质疑当中,质疑 4 是分析的比较中肯的,其清晰的概念分析该让我们对 CAP 有更深入的理解!

就像 Lynch 所说,现在分布式系统有很多特性,比如扩展性、优雅降级等,虽着时间的发展,或许这些也会被纳入研究范畴,而作为开发者,这都是我们需要考虑的问题,而不仅是 CAP 三者!


参考文献

Practical Understanding of FLP Impossibility for Distributed Consensus wikipedia.CAP定理 Deconstructing the `CAP theorem’ for CM and DevOps Errors in Database Systems, Eventual Consistency, and the CAP Theorem How to beat the CAP theorem cap-confusion-problems-with-partition-tolerance Perspectives on the CAP Theorem

0 人点赞