拜托,请不要再曲解CAP定理

参考文章

CAP theorem - Wikipedia
Please stop calling databases CP or AP
ACID - Wikipedia
Eventual_consistency - Wikipedia
CAP和BASE理论

前言

特定理论的英文缩写一向是程序员装逼最趁手的工具, 两个程序员交流时, 如果一方想要抛出一个自己了解过的高级概念并试探性地进行智商碾压时, 必然要在谈吐间夹带一些英文字母, 并暗示你, 如果你没听过这个英文缩写, 就快点接受我的观点。

CAP, BASE 就是上述的装逼利器之一, 而且有点烂大街。 很多程序员甚至不屑于过多使用它们, 因为他们仿佛是分布式系统的最容易掌握的入门知识点。

遗憾的是, 很多人为了满足装逼需求, 只是粗浅地翻阅一些网络博文, 对这几个概念没有准确理解, 就夸夸奇谈。本文旨在帮助有兴趣的初学者, 正确而清晰地掌握这几个并不粗浅的概念及其关联的其他知识点。如下两个误解可供读者检验是否有必要阅读本文。

CAP 定理误用一

在分布式系统设计中, 必须选择性放弃C、A、P 三种性质中的一种(错误!!!

CAP 定理误解二

设计系统时, 我们要么追求设计一个 CP 系统, 要么追求设计一个 AP 系统(不准确

CAP 定理(不建议称为 CAP 理论)

首先值得强调的是, CAP, ACID, BASE 这三个常常关联出现的英文缩写中, CAP 的地位是最高的, 只有 CAP 可以称作定理(Therom), 没错, 就是数学含义的定理, 它是指受逻辑限制的证明为真的陈述, 几乎不容反驳, 除非你推翻定理证明的前置定理和基本的逻辑学。 所以这里强烈建议读者看到 CAP, 就将其称为定理, 而非一种理论, 因为不是所有的理论都被严格证明为真。

CAP 定理最先是2002年由加州伯克利分校的 Eric Brewer 提出的一个猜想, 而这一猜想的证明,是2年之后由麻省理工学院的 Seth Gilbert 和 Nancy Lynch 证明的, 光是这一点就足以说明这一定理并不是一个简单的概念。

CAP 定理的出现就像一盏明灯, 在茫茫的学术海洋中, 为众多探索者指明了清晰的方向, 避免了很多不必要的尝试与研究

它的结论非常简单: 一个分布式系统不可能同时满足 C, A, P 这三个字母分别描述的三个属性, 只能满足其中两个。

上面这个部分, 几乎所有知道这个概念的人, 都能正确背诵,但是很多人都不能准确的描述 C, A, P 每个英文字母所代表的含义。 要知道一个数学定理的概念定义一定是非常精确的, 含义的轻微修改都可能导致定理的失效, 以致于提出这个概念猜想 Eric Brewer 本人都在公开发布的文章中承认,有关 CAP 定理指导分布式系统设计 “三选二” 的说法,是一种具有误导性, 或者错误的定理应用。

在这里插入图片描述

一致性(Consistency)

Consistency: Every read receives the most recent write or an error

一致性: 每一次读请求都能获得最近一次写操作的结果或是一个错误。

上面这句话看起来非常简单, 但是读者必须要注意把它放到分布式系统的语境中进行理解。

  1. 多个读请求, 要允许来自不同的客户端。
  2. 多个读请求, 可能被转发到不同的服务器结点上(系统对外暴露哪些结点, 由系统设计者定义,但通常,分布式系统都会定义多个结点接收客户端请求,并且允许水平扩展, 否则就会存在单节点瓶颈, 失去了分布式系统设计的初衷)
  3. 多个读请求中可能穿插着任意的写请求,读写请求的发起顺序和到达系统的顺序是不被保障的。
  4. 如果读请求无法满足上面的要求, 服务器可以拒绝读请求, 也就是返回了错误。

整个系统的读写交互过程可能是如下这样杂乱无章的, 当然, 你也可以对外提供一个专用结点, 用于接收所有客户端的请求, 但是很明显, 你需要考虑如何解决,单节点发生故障导致整个系统不可用的问题
在这里插入图片描述
需要再三强调的是, CAP 定理中的 Consistency , 与 ACID 中的 Consistency 是完全不一样的概念!!! , 这一点在本文后续会再次被强调。

此处的一致性含义更不容易被误读的一种命名是 “Linearizablity” , 其含义是:

  • 任意一个写请求A 被系统成功处理后, 系统紧接着收到的读请求B, 无论是系统中的哪个结点收到的(只要设计者允许该结点接收读请求),都必须能成功感知到 A 操作所带来的影响。

可用性(Availability)

Availability: every request received by a non-failing node in the system must result in a [non-error] response

可用性: 每一次被非失败结点收到的请求, 都可以获得一个非错误的正常响应。

关于可用性这一特性, 也是不少人没有完全理解的特性之一。 简单的问 2 个问题:

  • 满足可用性的系统, 是一个 7 * 24 小时百分之百不会终止工作的系统吗,这样的系统存在吗
  • 如果系统中的部分结点允许失败, 这个比例有什么要求吗

显然, 没有任何一个系统,可以保证百分之百不失败, 这里的可用性其实描述的是:

  • 对客户端而言, 你的分布式系统, 可能内部已经有部分甚至大量结点宕机, 但如果还有结点允许处理客户端请求且能成功接收请求时, 被收到到的每个请求都是否能成功处理并予以返回

分区容忍性(Partition tolerance)

Partition tolerance: The system continues to operate despite an
arbitrary number of messages being dropped (or delayed) by the network
between nodes

分区容忍性: 即使系统内部结点间的任意数量的通信信息都可能被延迟或丢失, 整个系统也能正常运作。

这一特性相比前两个特性不复杂, 但是依旧有不少人将其错误理解为某分区,或某部分结点无故障时, 整个系统依旧正常运行。

正确理解这一特性的关键点是, 该特性描述的是通信故障对系统的影响而非结点故障对系统的影响。 由于分布式系统中存在多个结点, 假如你试图在多个结点中同步数据会进行某种协同指令操作, 必然涉及到网络通信, 而网络通信是没有必达保障的, 分区的概念描述的是一部分结点间失去联系, 但是这些结点还可以和外部通信的状态。

例如下图, Server2, Server3 无法与 Server1 正常通信,但是Server2,Server 3 之间可以相互通信, 导致整个系统形成了两个网络分区,这两个网络分区均可以和外界客户端正常交互。
在这里插入图片描述
分区容忍性即是在询问,这种情形下, 你的系统还能否如你所期待的那样 “正常” 工作。

正确理解 CAP 定理

从字面上来说, CAP 定理好像是在说一个任意 “三选二” 的事情, 但事实上, 只要你的系统是基于互联网通信, 那么信息都没有必达保障, 都会存在延迟会丢失信息的问题, 所以你设计的系统, 是一定需要满足 “Partition Tolerance” 这一属性的, 所以在这一属性上, 你其实并没有什么选择

那么是否就可以说, CAP 定理指导我们要么设计一个 CP 系统, 要么设计一个 AP 系统呢?

很遗憾,这种说法也不正确。 因为 CAP 定理中的 Consistency 与 Availability 实际含义是一个非常精确, 也就是我们之前提到的 Linerazability, 很多系统在这种严格定义下, 既不是 AP 系统也不是 CP 系统

一个简单的例子是 ZooKeeper, 由于 ZooKeeper 使用到了共识算法(Consensus Algorithm), 不少人理所当然的认为它是一个 CP 系统, 但是如果严格使用 CAP 定理中的定义来审视, 在一般情况下,它既不 CP, 也不 AP。 原因如下:

  • 客户端可以连接到 ZooKeeper 系统中的多个服务器,默认情况下,你的读请求并不能返回反生在其他服务器的刚刚的写操作结果。 此时, ZooKeeper 不满足 CAP 中的 C 属性

  • 而当网络分区发生时, 含有少数结点的分区只能处理读请求, 无法成功处理写请求并进行响应。 此时, ZooKeeper 不满足 CAP 定理中的 A 属性。

但是, 如果在发给 ZooKeeper 的读请求前, 都追加一个 sync 指令, ZooKeeper 系统就可以满足 CAP 定理中 C 的属性。

综上, 如果 CAP 定理不能简单解读为一个指导我们 “三选二” 设计系统的定理, 它的核心价值是什么呢? 我们可以试着从它的近似不严谨证明的过程去理解。

最简化的情况下, 我们有两个系统结点, 能够分别处理客户端的读写请求, 由于网络通信是不可靠的, 我们看网络分区时会发生什么。
在这里插入图片描述
假设这里我们 结点A 和 结点B 相互存储了对方的副本数据, 我们要求系统满足 CAP 中的 AP 属性, 即在这种情况下, 两个结点都要能正常处理客户端发来的请求, 看能否实现 C 的属性。

当网络分区发生时, 结点B 收到的读请求, 是无论如何无法感知到发生在 结点 A 的写操作的。 所以结点B 对于 2.b 这一读请求, 要么返回一个不满足 C 属性的响应,要么返回一个错误提示。 但是如果返回一个错误提示的话, 显然违背了 A 属性要求正常工作的结点不能返回错误信息的要求。

粗一看, 好像这个过程指导我们鱼(Consistency)与熊掌 ( Avaliablity) 不可兼得

但设想一下, 我们如果允许 结点B 返回错误信息并附带一个指示, 指导客户端向其他结点发送请求呢?系统是否某种意义上又是 “可用” 的呢? 它只是不满足CAP定理数学意义上的 可用性(Avaliablity)

从上面的例子可以看出来, CAP 定理的核心是向我们揭示了是一个网络通信不可靠的环境下, 分布式系统设计所需要面临的设计困境。 而不是让我们简单的把系统设计目标定位 AP 或 CP, 更不是将已有的分布式系统归类为 AP 或 CP 进行选用。 它引导我们去思考分布式系统设计中的核心矛盾, 这也就引出了后续的关联知识点 ACID 与 BASE 。

ACID 四性质

前面强调过, CAP 定理中的 Consistency 和 ACID 性质里的 Consistency 是两种完全不同的概念, 但是为什么又要把他们放在一起讨论呢 ?

原因是, CAP 定理向我们揭示的系统设计中的 Linearizability 问题, 常常会进一步转化为, 如何使分布式系统实现多结点的副本数据一致性, 而多结点的副本数据一致性问题, 往往又会转化为如何实现分布式事务问题, 即一个写操作如何确保它只要成功, 就同时在多个结点成功, 一旦失败, 就在多个结点同时失败。 而 ACID 这四个性质, 恰恰就是用于准确描述事务的。

ACID 和 CAP 有点相似的地方时, 它也提到了一些需要被计算机系统满足的性质,字面上 acid 这一单词作为形容词, 也是“酸性的” 含义, 可以辅助我们记忆这个概念描述的是一种性质而非一种定理

如果一个数据库系统的一系列操作能够满足 ACID 这四个属性, 我们就可以将其称为一个事务:

  • Atomicity 原子性
    • 一个事务中的多个操作对外表现得就像一个化学原子一样, 不可分割, 要么都成功, 要么都失败
  • Consistency 一致性
    • 这是四个属性中最容易被误解的一个属性
    • 数据库事务的一致性概念,最早在 Jim Gray 的论文中提出, 原文如下
    • Consistency: the transaction must obey legal protocols.
    • 上面的这个定义其实说的非常宽泛, 一种简单的理解是, “一致性” 这一性质要求一个事务成功后, 只能把数据库的状态从一个正确的状态转移至另外一个正确的状态。
    • 那么如何定义这个正确性呢, 一部分人认为这个正确性应该定义为数据库各种强制性的约束(比如主键约束, 外键约束), 即发生违反约束的情况应当导致事务回滚。 另一部分人认为, 这个正确性应当推广到应用层的业务含义约束, 比如, 转账前后, A账户 + B账户的钱一定要是固定的一个值。
    • 这两种正确性的理解笔者认为均可, 都不妨碍对于事务这一概念的理解。需要注意的是, 该一致性的概念和 CAP 理论中的一致性, 并不一样!!!
    • CAP理论中的一致性, 强调的是一个读写操作线性序列化的概念, 即一次读操作, 必然能够返回最近一次成功的写操作的影响。 而 ACID 中的一致性,强调的是, 一个事务的开始前状态和结束后的数据库状态, 都需要满足数据库正确性的定义
  • Isolation 隔离性
    • 并发执行的多个事务结束后使数据库达到的状态应当和这些事务不并发, 依次顺序执行的结果一样。
    • 这一性质主要关注事务并发执行的效果, 比较好理解, 不作过多赘述
  • Durability 持久性
    • 事务一旦被成功提交, 即使立刻发生系统宕机, 已经提交的事务记录应当依旧有效。

关于 ACID 事务在单机数据库中如何实现, 这里不作赘述,需要我们知道的是, 分布式系统如果想实现一个 ACID 事务, 并不容易, 被提出的代表性方案是 二阶段提交协议(Two-Phase Commit)。笔者在另外一篇博文中也有介绍 正确理解二阶段提交协议

基于 ACID 分布式事务不易实现的背景下, BASE 作为一个 ACID 的替代选项被提了出来

BASE 四性质

BASE 单词作为形容词, 字面上恰好是 ACID 的化学对立面, “碱性的”, 非常容易记忆。 但是其中的性质与 ACID 的关系却不是对立的。 展开来说, BASE (Basically Available, Soft state, Eventual consistency) 描述的三个性质:

  • Basically Available 基本可用
  • Soft state 柔性状态
  • Eventual consistency 最终一致性

显而易见的是, BASE 所描述的约束, 是比 ACID 更宽松的约束, 一个满足 ACID 的系统, 必然是轻易满足 BASE 的, 反之则不能成立。 所以酸碱性的记忆仅限于名词的关联记忆, 不可做含义引申。

需要指出的是, BASE 这一提法, “最终一致性的概念”, 并不像 ACID 那样, 每一个都有精确且独立的定义。 最早提出这一缩写的是 eBay 架构师 Dan Pritch-ett 在 ACM Queue 这一杂志上发布的文章BASE: An Acid Alternative, 文章中 Soft State 与 Eventrually Consistent 也被当做是几乎相同的概念。

所以关于 BASE 理论, 不必像 CAP 或 ACID 那样精确的探究每一个字母的含义, 只要把握住最终一致性这一核心概念, 并且理解其放松了 CAP 定理中可用性定义的即可。

笔者个人也不建议把 BASE 作为一个常用的名词来描述问题, 毕竟一切不清晰的定义, 都是误解和错误产生的来源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章