1. CAP理论的历史
2000年7月,Eric Brewer教授提出CAP猜想;2年后,Seth Gilbert和Nancy Lynch从理论上证明了CAP;之后,CAP理论正式成为分布式计算领域的公认定理。
2. CAP的背景和定义
CAP理论讨论的对象是分布式场景。一个分布式系统需要满足三个最基本的特性,分别是一致性(Consistency)、可用性(Availability)和分区容错性(Partition Tolerance,这个中文翻译很不直观,没能体现Partition原来的意思,这也人为拉高了理解成本,至少对以前的我是这样,后面会单独介绍)。CAP理论的简单解释就是,不可能存在一个完美的分布式架构,能同时满足这三个特性。架构师们不要试图花精力去设计一个“完美”的架构来满足这三个特性,而是应该因地制宜,根据实际的需求在CAP之间做权衡。
这里也只是从字面意思对CAP做了个翻译,并不便于理解,下面结合一个具体的例子来说明。
下图是一个假想的最小(典型的)分布式应用场景:
- 两台服务器Node1, Node2(在分布式环境中,习惯叫节点)构成一个服务集群,对外提供服务
- 客户Client可以随机访问任何一台服务器上的服务
- 两台服务器内部之间也可以互相访问
这个简单的分布式系统需要满足哪些特性才算得上是一个比较好的系统(产品)呢?思考以下几个场景:
客户访问Node1时写入了一个数据(比如往账户存了100元),当客户要读取该值时又随机访问了Node2,系统需要保证Node2也能够返回正确的值,这个就是所谓的一致性要求(Consistency)。
一致性的权威解释如下(来自证明CAP理论的原作者):
当客户访问某个节点时,如果该节点正常工作,系统需要保证该节点必须要给客户一个响应(可以是错误的响应,也可以有一定的延迟,但是不能没有响应),也就是说任何时刻必须保证请求能得到响应,这就是系统的可用性要求(Availability)
在分布式环境中,每个节点都不是可靠的,各节点之间的通信也可能出问题。当某些节点出现故障(或者节点本身的故障,或者部分网络故障)时,整个系统就产生了所谓的”分区“。当系统产生”分区“的时候,如果还能对外提供比较好的服务(例如较好的一致性和可用性),就可以说该系统具有较好的”分区容错性“(Partition Tolerance)。
如果对分区还不好理解的话,看看partition的英文解释吧:
(n.) a wall or screen that separate one part of a room from another
(v.) to separate one area, one part of a room, etc. from another with a wall or screen
就是分割、隔离的意思,也就是说因为某些原因,部分节点被隔离到集群之外的时候,整个系统还能够正常工作,对外表现得就像没事儿一样。
3. CAP为什么不能同时满足
有兴趣深入了解的同学,可以在这里看原始的证明:
https://groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf
浅显易懂点的,可以参考这篇文章:
https://mwhittaker.github.io/blog/an_illustrated_proof_of_the_cap_theorem/
再简单点的解释就是这样,考虑下面的一个场景:
Client写入数据到Node1;Node2出现分区导致Node1的数据没有同步到Node2;Client访问Node2读取数据
- 同时满足AP:系统保证在Node2出现分区的情况下,还能立即返回结果给Client。但此时Node2还没有同步到Node1的数据,所以没法保证数据的一致性
- 同时满足CP:系统保证在Node2出现分区的情况下,能返回一致的结果给Client。这个只能等到Node2正确同步到Node1的数据之后才能返回(有可能永远同步不了),因此不能立即返回(也可能永远无法返回),也就失去了可用性
- 同时满足CA:Node2能保证返回准确一致的数据给到Client,但考虑到这是一个分布式系统,是没法保证每个节点都能正常工作不产生分区的(虽然集群的所有节点同时出现故障的概率非常低,但是单个节点出现故障的概率还是比较高的)
4. CAP理论在现实中的应用
既然理论是这样,我们就不要浪费时间去设计完美的分布式系统,这就是方法论起的作用。
考虑到在分布式场景中,系统产生分区的情况无法避免,我们就只能尽量提供一个比较好的”分区容错性“的产品。换句话说,我们需要在系统出现分区的时候,在一致性和可用性之间做权衡。
CP:优先保证数据的一致性,在数据没有一致的情况下,可以适当降低系统的可用性,比如放弃当前的请求,让客户端重试;或者降低对客户端的响应速度(比如银行转账结束时等待5s的提示界面)。ZooKeeper被设计为在分布式系统中协调服务、保证各服务节点数据一致的产品,就是CP的例子。还有各种分布式数据库产品,如Redis、HBase,也都是偏向数据一致性的CP的例子。
AP:优先保证系统的可用性,降低数据的一致性诉求。比如电商网站的下单界面展示的可购买数量,这个是时时变化的。如果要保证一致性,则需要系统时时刷新获取最新的数据,势必会影响网站的响应速度,也就降低了可用性,影响用户体验(可以改为在真正下单的那一刻再提示库存是否满足下单条件)。
实际上,随着基础设施越来越完善,分布式系统中出现P的情况也可以控制的越来越精细。在不用特别担心P的情况下,系统在大多数情况下是可以做到完美的C和A的,具体可参考原作者的另外一篇文章(强烈推荐):CAP 理论十二年回顾:"规则"变了
中文版:https://www.infoq.cn/article/cap-twelve-years-later-how-the-rules-have-changed
英文版:https://www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed