CAP 定理,只能三选二吗?
大家好,我是猿java。
不管你有没有实战过分布式系统,赫赫有名的 CAP 定理一定有所耳闻,今天我们就来聊一聊 CAP 是什么?在分布式系统设计时,CAP 该如何选择?
CAP 由来
CAP 定理:CAP Theorem,又被称作布鲁尔定理(Brewer’s theorem),它是由加州大学伯克利分校教授埃里克·布鲁尔(Eric Brewer)在 2000 年首次提出,主要是关于搜索引擎、分布式 Web 缓存权衡的一个猜想,直到 2002 年,麻省理工学院的赛斯·吉尔伯特(Seth Gilbert)和 南希·林奇(Nancy Lynch)才提出和发表对该猜想的正式证明,使之成为分布式计算领域公认的一个定理。
埃里克·布鲁尔:
- 博士
- 加州大学伯克利分校教授
- Inktomi 联合创始人兼首席科学家
布埃里克·布鲁尔 CAP 定理猜想
https://people.eecs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf
CAP 定义
如果你仔细研读过埃里克·布鲁尔 CAP 猜想原文,会发现:在原文,作者并没有详细定义 Consistency、Availability、Partition Tolerance 三个词,因此,作为初学者甚至工作多年的小伙伴,因为学习 CAP 资料的不同,对 CAP 的理解也有所差别。
本文对 CAP 的定义基于 Seth Gilbert 和 Nancy Lynch 的 CAP 证明。
Seth Gilbert 和 Nancy Lynch 的 CAP 证明
C:Consistency,一致性
这里的一致性是指强一致性( Strong Consistency )或者线性一致性(Linearizable Consistency ),它要求多节点组成的分布式系统,能够像单节点一样,如果一个写操作返回成功,后面所有的读请求都必须能读到这个新数据,如果写操作返回失败,后面所有的读操作都不能读到这个数据。因此,CAP 中的一致性忽略了网络延时,要求分布式系统节点数据的写入能和单机一样即时。
A:Availability,可用性
可用性要求系统提供的服务必须处于 100% 可用的状态,对于用户的每一个操作请求,系统总能够在有限的时间内返回结果。这里强调的可用性是完全可用,不允许任何不可用的情况出现,因此这是一个非常理想的模型。
目前业内的分布式系统根本达不到 100% 的可用性,常见的可用性有:99.99% (俗称 4 个 9),即一年内服务不可用时长有 50 分钟;99.999%(俗称 5 个 9),即一年内服务不可用时长只有 5 分钟,99.9999%(俗称 6 个 9),即一年内服务不可用时长只有 31秒。
P:Partition tolerance,分区容错性
分区指的是在整个分布式系统中,因为各种网络原因,导致系统被分隔成多个独立的部分,它不仅包含通常意义上的网络分区,也包含因网络丢包导致网络不通的情况。因此,分区容错是指当出现网络分区后,系统能够继续“履行职责”。
如下图:因为网络分区,ATM1 成了一个独立的区域,ATM2 和 ATM3 又成了另外一个区域。
CAP 组合
按照 CAP 定理,三个要素中只能取两个,组合如下图:
CA - Consistency/Availability
如下图:账户原余额是 0,在网络状况 ok 时,从 ATM1 存入 $100 ,再从 ATM2 查询余额也是 $100。所以,可以满足 CA。
但是,作为一名程序员,应该很清楚:日常开发中,很多工作都是为了弥补网络异常导致的问题。因此在真实的分布式环境中,网络状况是一个不确定因素,假如忽略网络状况(即忽略 P),只考虑 CA 会出现什么情况?
如下图:账户原余额是 0,当 ATM1 存入 $100 成功后, ATM1 和 ATM2 发生网络分区,为了保证两个 ATM 数据的 C(一致性),ATM 2 需要禁止存款,查询余额等操作,这样 ATM2就不能工作了,和 A(可用性) 冲突;
如下图:当 ATM1 存入 $100 成功后, ATM1和 ATM2 发生网络分区,为了保证两个 ATM 系统的 A(可用性),ATM2 就必须提供存款,查询余额等操作,但是 ATM1 存入 $100 的信息还未同步给 ATM2,所以,ATM2查询到的账户余额是 0,余额不足,和 C(一致性) 冲突;
因此,分布式系统,理论上是不能选择 CA 架构。
CP - Consistency/Partition tolerance
如下图:账户原余额是 0,当从 ATM1 存入 $100 时发生了网络分区,ATM1 和 ATM2 无法通信,因此,从 ATM1 上存入 $100 的信息无法同步给 ATM2,ATM2 为了保证和 ATM1 数据的一致性,需要拒绝存款或者查询余额等操作,返回 error,这样就牺牲了ATM2 的 A(可用性)。
AP - Availability/Partition tolerance
如下图,账户原余额是 0,当从 ATM1 存入 $100 时发生了网络分区,ATM1 和 ATM2 无法通信,为了保证可用性,ATM 2 必须提供存款,查询余额等操作。注意:尽管 ATM2提供了服务,但是它提供的数据可能是一个错误的,因此牺牲了 C(一致性)。
上文我们用实例分别描述了 CA,CP,AP,因为现实环境中,网络的因素是不可控的,所以在大部分情况下,系统设计都会保留 P 属性,而在 C 和 A 中二选一。但是,在分布式系统的设计中,真的只能三选二吗?
CAP 误区
误区一:* *三选二有误导性**
这里是一个很容易产生误解的地方,很多资料都强调 CAP 只能选择 CP 或者 AP,但是在计算机的世界,并不是非黑即白。
CAP 定理阐明分布式系统只能选择 CP 或 AP,但这里有一个隐藏的前提:那就是系统发生了“分区”。由于分区很少发生,如果系统不存在分区的情况下没有理由牺牲 C 或 A ,CAP 在大多数时候允许完美的 C 和 A。因此,在架构设计时,既要考虑分区发生时选择 CP 还是 AP,也要考虑没有网络分区时如何保证 CA。
误区二:牺牲不等于什么都不做
CAP 定理阐明三个元素只能取两个,需要“牺牲”(sacrificed)另外一个,这里的“牺牲”只是说在分区时无法同时保证 CA,并不是什么都不做。比如:上文提到的 99.99%、99.999% 或 99.9999% 系统,一年内不可用时长不超过 1小时,因此可以在分区期间牺牲 C 或 A,在分区故障解决后,系统又重新恢复到 CA 状态。
误区三:CAP 忽略了网络延时
CAP 定理的强一致性,要求分布式系统和单点系统一样保证数据写入的即时性,忽略了节点间数据复制有网络延时(也就是说,当有数据写入时,数据能够瞬间复制到所有节点)。实际情况下,数据从节点 A 复制到节点 B,需要花费一定的时间。这就意味着,CAP 理论中的 C 在实践中是不可能完美实现的,在数据复制的过程中,节点 A 和节点 B 的数据并不一致。
通过分析几个误区,我们来回答文章标题:CAP 只能 三选二吗?
CAP 中阐述只能选择 CP 或者 AP,前提是系统出现了分区,存在误导性,因为分区比较少发生,因此在网络状况良好的,CAP都是可以保证的,在架构设计时,既要考虑分区发生时选择 CP 还是 AP,也要考虑没有网络分区时如何保证 CA。
ACID 和 BASE
分析完 CAP 之后,就不得不提和 CAP 有千丝万缕关系的 ACID 和 BASE。
ACID 是数据库的传统设计思路,CAP 与 ACID 容易产生误解的一个原因是 ACID 和 CAP有相同的 C、A 字母,但是它们所代表的概念却不同。
A:ACID 中的 A 是 Atomicity,原子性。一个事务中的所有操作,要么全部完成,要么全部失败。CAP 中的 A 是可用性。
C:ACID 中的 C 是 Consistency,一致性。指事务不能破坏任何数据库规则,如键的唯一性。与之相比,CAP 的 C 仅指单一副本这个意义上的一致性,因此只是 ACID 一致性约束的一个严格的子集。
I:Isolation,隔离性。正在处理但尚未提交的事务必须与任何其他事务保持隔离。事务隔离分为:读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。隔离是 CAP 定理的核心:如果系统要求 ACID 隔离性,那么它在分区期间最多可以在分区一侧维持操作。事务的可串行性(serializability)要求全局的通信,因此在分区的情况下不能成立。只要在分区恢复时进行补偿,在分区前后保持一个较弱的正确性定义是可行的。
D:Durability,持久性。事务对数据的修改就是永久的,即便系统故障也不会丢失数据。
BASE,它是 “Basically Available, Soft state, Eventually consistent(基本可用、软状态、最终一致性)”的首字母缩写。其中的软状态和最终一致性这两种技巧擅于对付存在分区的场合,提高了可用性。BASE 中的最终一致性其实是对 CAP 强一致性的一个补充。
真实案例
CP 系统
Redis、Google BigTable、Hbase、MongoDB、 MemCacheDB
AP 系统
亚马逊的 DynamoDB、以及衍生物 Apache Cassandra 和 Voldemort
CA 系统
Apache Kafka 是一个比较典型的 CA系统
Kafka 从 0.8 版本之后,引入了 Replication 副本的概念。通过 In-sync-replica(同步数据副本)机制,所有的数据写入都必须在这个领导者节点中记录。另外,通过将数据复制到不同的节点上,从而增强了数据在系统中的持久性(Durability)和可用(Availability)。在 Kafka Replication 的系统设计中,所有的数据日志存储是设计在同一个数据中心(Data Center)里面的,也就是说,在同一个数据中心里网络分区出现的可能性是十分之小的。
总结
CAP 是作者埃里克·布鲁尔 的猜想,经过麻省理工学院 赛斯·吉尔伯特(Seth Gilbert)和南希·林奇(Nancy Lynch)的证明。CAP 定理是分布式的一个基础理论,它可以开阔设计师的思路,在多样化的取舍方案下设计出多样化的系统。
CAP 定理强调的是强一致性和 100% 服务可用,但是,在真实分布式环境中 100% 可用只能是一种理想的状态。因此,4个9、5个9、6个9 的系统, 哪怕它不符合 CAP 定理的可用性,也符合工作中对可用性的要求。CAP 的强一致性,在分布式环境的多个节点间,因为数据同步有网络延时,因此也会存在一段时间的不一致。
CAP 定理断言任何基于网络的数据共享系统,最多只能满足数据一致性、可用性、分区容忍性三要素中的两个要素。但是通过显式处理分区情形,系统设计师可以做到优化数据一致性和可用性,进而取得三者之间的平衡。
百种业务百种架构,在架构设计时,既要考虑分区发生时选择 CP 还是 AP,也要考虑没有网络分区时如何保证 CA。
参考文献
Seth Gilbert 和 Nancy Lynch 的 CAP 证明
CAP Twelve Years Later: How the “Rules” Have Changed
CAP Twelve Years Later: How the “Rules” Have Changed 中文版
学习交流
如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。