gitbook/从0开始学架构/docs/9302.md
2022-09-03 22:05:03 +08:00

167 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 22 | 想成为架构师你必须知道CAP理论
CAP定理CAP theorem又被称作布鲁尔定理Brewer's theorem是加州大学伯克利分校的计算机科学家埃里克·布鲁尔Eric Brewer在2000年的ACM PODC上提出的一个猜想。2002年麻省理工学院的赛斯·吉尔伯特Seth Gilbert和南希·林奇Nancy Lynch发表了布鲁尔猜想的证明使之成为分布式计算领域公认的一个定理。对于设计分布式系统的架构师来说CAP是必须掌握的理论。
布鲁尔在提出CAP猜想的时候并没有详细定义Consistency、Availability、Partition Tolerance三个单词的明确定义因此如果初学者去查询CAP定义的时候会感到比较困惑因为不同的资料对CAP的详细定义有一些细微的差别例如
> **Consistency**: where all nodes see the same data at the same time.
>
> **Availability**: which guarantees that every request receives a response about whether it succeeded or failed.
>
> **Partition tolerance**: where the system continues to operate even if any one part of the system is lost or fails.
([https://console.bluemix.net/docs/services/Cloudant/guides/cap\_theorem.html#cap-](https://console.bluemix.net/docs/services/Cloudant/guides/cap_theorem.html#cap-))
> **Consistency**: Every read receives the most recent write or an error.
>
> **Availability**: Every request receives a (non-error) response without guarantee that it contains the most recent write.
>
> **Partition tolerance**: The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes.
([https://en.wikipedia.org/wiki/CAP\_theorem#cite\_note-Brewer2012-6](https://en.wikipedia.org/wiki/CAP_theorem#cite_note-Brewer2012-6))
> **Consistency**: all nodes have access to the same data simultaneously.
>
> **Availability**: a promise that every request receives a response, at minimum whether the request succeeded or failed.
>
> **Partition tolerance**: the system will continue to work even if some arbitrary node goes offline or cant communicate.
([https://www.teamsilverback.com/understanding-the-cap-theorem/](https://www.teamsilverback.com/understanding-the-cap-theorem/))
为了更好地解释CAP理论我挑选了Robert Greiner[http://robertgreiner.com/about/](http://robertgreiner.com/about/)的文章作为参考基础。有趣的是Robert Greiner对CAP的理解也经历了一个过程他写了两篇文章来阐述CAP理论第一篇被标记为“outdated”有一些中文翻译文章正好参考了第一篇我将对比前后两篇解释的差异点通过对比帮助你更加深入地理解CAP理论。
## CAP理论
第一版解释:
> Any distributed system cannot guaranty C, A, and P simultaneously.
[http://robertgreiner.com/2014/06/cap-theorem-explained/](http://robertgreiner.com/2014/06/cap-theorem-explained/)
简单翻译为对于一个分布式计算系统不可能同时满足一致性Consistence、可用性Availability、分区容错性Partition Tolerance三个设计约束。
第二版解释:
> In a distributed system (a collection of interconnected nodes that share data.), you can only have two out of the following three guarantees across a write/read pair: Consistency, Availability, and Partition Tolerance - one of them must be sacrificed.
[http://robertgreiner.com/2014/08/cap-theorem-revisited/](http://robertgreiner.com/2014/08/cap-theorem-revisited/)
简单翻译为在一个分布式系统指互相连接并共享数据的节点的集合当涉及读写操作时只能保证一致性Consistence、可用性Availability、分区容错性Partition Tolerance三者中的两个另外一个必须被牺牲。
对比两个版本的定义,有几个很关键的差异点:
* 第二版定义了什么才是CAP理论探讨的分布式系统强调了两点interconnected和share data为何要强调这两点呢 因为**分布式系统并不一定会互联和共享数据**。最简单的例如Memcache的集群相互之间就没有连接和共享数据因此Memcache集群这类分布式系统就不符合CAP理论探讨的对象而MySQL集群就是互联和进行数据复制的因此是CAP理论探讨的对象。
* 第二版强调了write/read pair这点其实是和上一个差异点一脉相承的。也就是说**CAP关注的是对数据的读写操作而不是分布式系统的所有功能**。例如ZooKeeper的选举机制就不是CAP探讨的对象。
相比来说,第二版的定义更加精确。
虽然第二版的定义和解释更加严谨但内容相比第一版来说更加难记一些所以现在大部分技术人员谈论CAP理论时更多还是按照第一版的定义和解释来说的因为第一版虽然不严谨但非常简单和容易记住。
第二版除了基本概念,三个基本的设计约束也进行了重新阐述,我来详细分析一下。
1.一致性Consistency
第一版解释:
> All nodes see the same data at the same time.
简单翻译为:所有节点在同一时刻都能看到相同的数据。
第二版解释:
> A read is guaranteed to return the most recent write for a given client.
简单翻译为:对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
第一版解释和第二版解释的主要差异点表现在:
* 第一版从节点node的角度描述第二版从客户端client的角度描述。
相比来说,第二版更加符合我们观察和评估系统的方式,即站在客户端的角度来观察系统的行为和特征。
* 第一版的关键词是see第二版的关键词是read。
第一版解释中的see其实并不确切因为节点node是拥有数据而不是看到数据即使要描述也是用have第二版从客户端client的读写角度来描述一致性定义更加精确。
* 第一版强调同一时刻拥有相同数据same time + same data第二版并没有强调这点。
这就意味着实际上对于节点来说可能同一时刻拥有不同数据same time + different data这和我们通常理解的一致性是有差异的为何做这样的改动呢其实在第一版的详细解释中已经提到了具体内容如下
> A system has consistency if a transaction starts with the system in a consistent state, and ends with the system in a consistent state. In this model, a system can (and does) shift into an inconsistent state during a transaction, but the entire transaction gets rolled back if there is an error during any stage in the process.
参考上述的解释,对于系统执行事务来说,**在事务执行过程中,系统其实处于一个不一致的状态,不同的节点的数据并不完全一致**因此第一版的解释“All nodes see the same data at the same time”是不严谨的。而第二版强调client读操作能够获取最新的写结果就没有问题因为事务在执行过程中client是无法读取到未提交的数据的只有等到事务提交后client才能读取到事务写入的数据而如果事务失败则会进行回滚client也不会读取到事务中间写入的数据。
2.可用性Availability
第一版解释:
> Every request gets a response on success/failure.
简单翻译为:每个请求都能得到成功或者失败的响应。
第二版解释:
> A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).
简单翻译为:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。
第一版解释和第二版解释主要差异点表现在:
* 第一版是every request第二版强调了A non-failing node。
第一版的every request是不严谨的因为只有非故障节点才能满足可用性要求如果节点本身就故障了发给节点的请求不一定能得到一个响应。
* 第一版的response分为success和failure第二版用了两个reasonablereasonable response 和reasonable time而且特别强调了no error or timeout。
第一版的success/failure的定义太泛了几乎任何情况无论是否符合CAP理论我们都可以说请求成功和失败因为超时也算失败、错误也算失败、异常也算失败、结果不正确也算失败即使是成功的响应也不一定是正确的。例如本来应该返回100但实际上返回了90这就是成功的响应但并没有得到正确的结果。相比之下第二版的解释明确了不能超时、不能出错结果是合理的**注意没有说“正确”的结果**。例如应该返回100但实际上返回了90肯定是不正确的结果但可以是一个合理的结果。
3.分区容忍性Partition Tolerance
第一版解释:
> System continues to work despite message loss or partial failure.
简单翻译为:出现消息丢失或者分区错误时系统能够继续运行。
第二版解释:
> The system will continue to function when network partitions occur.
简单翻译为:当出现网络分区后,系统能够继续“履行职责”。
第一版解释和第二版解释主要差异点表现在:
* 第一版用的是work第二版用的是function。
work强调“运行”只要系统不宕机我们都可以说系统在work返回错误也是work拒绝服务也是work而function强调“发挥作用”“履行职责”这点和可用性是一脉相承的。也就是说只有返回reasonable response才是function。相比之下第二版解释更加明确。
* 第一版描述分区用的是message loss or partial failure第二版直接用network partitions。
对比两版解释第一版是直接说原因即message loss造成了分区但message loss的定义有点狭隘因为通常我们说的message loss丢包只是网络故障中的一种第二版直接说现象即发生了**分区现象**,不管是什么原因,可能是丢包,也可能是连接中断,还可能是拥塞,只要导致了网络分区,就通通算在里面。
## CAP应用
虽然CAP理论定义是三个要素中只能取两个但放到分布式环境下来思考我们会发现必须选择P分区容忍要素因为网络本身无法做到100%可靠有可能出故障所以分区是一个必然的现象。如果我们选择了CA而放弃了P那么当发生分区现象时为了保证C系统需要禁止写入当有写入请求时系统返回error例如当前系统不允许写入这又和A冲突了因为A要求返回no error和no timeout。因此分布式系统理论上不可能选择CA架构只能选择CP或者AP架构。
1.CP - Consistency/Partition Tolerance
如下图所示为了保证一致性当发生分区现象后N1节点上的数据已经更新到y但由于N1和N2之间的复制通道中断数据y无法同步到N2N2节点上的数据还是x。这时客户端C访问N2时N2需要返回Error提示客户端C“系统现在发生了错误”这种处理方式违背了可用性Availability的要求因此CAP三者只能满足CP。
![](https://static001.geekbang.org/resource/image/6e/d7/6e7d7bd54d7a4eb67918080863d354d7.png)
2.AP - Availability/Partition Tolerance
如下图所示为了保证可用性当发生分区现象后N1节点上的数据已经更新到y但由于N1和N2之间的复制通道中断数据y无法同步到N2N2节点上的数据还是x。这时客户端C访问N2时N2将当前自己拥有的数据x返回给客户端C了而实际上当前最新的数据已经是y了这就不满足一致性Consistency的要求了因此CAP三者只能满足AP。注意这里N2节点返回x虽然不是一个“正确”的结果但是一个“合理”的结果因为x是旧的数据并不是一个错乱的值只是不是最新的数据而已。
![](https://static001.geekbang.org/resource/image/2c/d6/2ccafe41de9bd7f8dec4658f004310d6.png)
## 小结
今天我为你讲了CAP理论通过对比两个不同版本的CAP理论解释详细地分析了CAP理论的准确定义希望对你有所帮助。
这就是今天的全部内容留一道思考题给你吧基于Paxos算法构建的分布式系统属于CAP架构中的哪一种谈谈你的分析和理解。
欢迎你把答案写到留言区,和我一起讨论。相信经过深度思考的回答,也会让你对知识的理解更加深刻。(编辑乱入:精彩的留言有机会获得丰厚福利哦!)