原文: https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html
中文版: https://blog.the-pans.com/cap/
现代化解读CAP,不要被CA,CP,AP术语所迷惑。
01 . 文章观点
CAP过于简单化,切容易被误解,应该用更精确的术语来理解系统设计上的权衡
?为什么说过于简单化
?怎么被误解的
?更精确的术语是什么
?实践上怎么体现
海尔耶迈的提问,不要用术语,如何描述你正在做和要做的东西,如果能通俗的描述出来,那你做的东西才是真的懂了。
02. 论点+批语
首先要理解CAP,其中C,A,P每个元素的各自含义
C
线性一致
线性一致是非常困难的,且不说在分布式环境下,就算是单机多核的情况下,也要通过内存屏障来处理
批语:并发要解决的一致性问题是单机的一致性问题,大而化之分布式,其实也是一样的,只是寄存器变成了每台服务器实例。建议看一下原文对于线性一致性的图示,非常经典。
A
- 可用性
P
- 分区容忍
!在分布式环境下分区是肯定需要考虑的,就是在P的前提下,对C和A进行取舍。
在集群产生网络分区的时候,你的系统是要选择能够继续提供服务还是为了数据一致性不再对外提供服务,CAP就是非此即彼的概念,在实际应用中,会尽可能的兼顾C和A,而不是单纯,简单的放弃。
- 你的应用还是被允许写到数据库,所以两边的数据库还是完全可用的。但是一旦两个数据库之间的网络中断了,任何一个数据中心的写操作就不会在另一个数据中心出现。这就违反了可线性化(用之前的例子,Alice可能链接到了一号数据中心,而Bob连接到了二号数据中心)。
2. 如果你不想失去可线性化,你就必须保证你的读写操作都在同一个数据中心,你可能叫这它leader。另一个数据中心,因为网络故障不能被更新,就必须停止接收读写操作,直到网络恢复,两边数据库又同步了之后。所以虽然非leader的数据库在正常运行着,但是他却不能处理请求,这就违反了CAP的可用性定义。
反证CAP的例子
单master的集群,如果master挂了,这时候不提供写服务,但是提供读服务,那肯定不满足,CAP中的A,由于这个集群是异步同步的,client有可能读到旧数据,那对于C也是不满足的。
而且如果要确保数据一致性,必须采用主-从复制模式,这个结论是有严格的数学论证
参考《消息队列高手课》22篇
所以这些系统既不是CAP一致的,也不是CAP可用的。他们既不是CP也不是AP,他们只是P,不管这是什么意思。(是的,“三选二”也允许你只从三个中选一个,甚至一个都不选!)
关于Zookeeper
zk 号称CP系统,
?zk怎么保证高可用
?zk能保证线性一致性吗
且看ZK官方文档的说明,摘录(原文:http://zookeeper.apache.org/doc/r3.4.6/zookeeperProgrammers.html#ch_zkGuarantees)
Sometimes developers mistakenly assume one other guarantee that ZooKeeper does not in fact make. This is:
Simultaneously Consistent Cross-Client Views
ZooKeeper does not guarantee that at every instance in time, two different clients will have identical views of ZooKeeper data. Due to factors like network delays, one client may perform an update before another client gets notified of the change. Consider the scenario of two clients, A and B. If client A sets the value of a znode /a from 0 to 1, then tells client B to read /a, client B may read the old value of 0, depending on which server it is connected to. If it is important that Client A and Client B read the same value, Client B should should call the sync() method from the ZooKeeper API method before it performs its read.
So, ZooKeeper by itself doesn't guarantee that changes occur synchronously across all servers, but ZooKeeper primitives can be used to construct higher level functions that provide useful client synchronization. (For more information, see the ZooKeeper Recipes. [tbd:..]).
ZK支持可线性化的读,但需要执行sync方法,每次都执行一次sync对于读操作来说,代价昂贵,所以这对于zk来说默认是不支持线性化读,属于给用户的一个可选项。
更有意思的是,ZooKeeper 3.4.0还加入了一个只读的模式。在这个模式下,少部分节点的分区还可以继续处理读操作 -- 不需要quorum! 这个读操作是满足CAP可用性的。所以ZooKeeper默认设置既不是一致的(CP)也不是可用的(AP),只是"P"。但是你有选择通过用sync命令来让它成为CP。并且在正确的设置下,读操作(不包括写)其实是CAP可用的。
为什么说一直被人称作CP系统的ZK,在默认设置下既不是CP也不是AP,只是P。不是AP可以这么解释,在发生P的时候,虽然一个有大多数节点的网络分区仍然能提供服务,但是少部分节点的分区却不能处理写请求,所以P的时候A是不被满足的。
?发生网络分区的时候多数原则的基数参照是用的原始分区的数量还是分区之后单个分区的数量,按照这个说明来说应该是原始集群的数量,但是怎么实现的,分区之后怎么知道原始集群有多少台
根据ZooKeeper的例子,你就会发现就算这系统在网络分区的时候既不是CP也不是AP(甚至在默认设置下,就算没有网络分区,也不是可线性化的),但他还是很合理的。(我猜ZK在Abadi的PACELC的框架下是PC/EL,但我不觉得这比CAP更有启发性。)
如果严格按照CAP来解释ZK,那ZK不是一个合格的系统,这也论述了cap的简单和单一,无法衡量一个系统的价值,说价值其实泛化了,但也没有找到合适的词来放这里。
结论
CP/AP 并不适合用来做描述系统的标签,作者的大致论点如下(非原文翻译,夹带私货)
C有很多种C,一个系统也可以提供多种一致性给用户选择
很多系统在严格CAP的定义下,只符合P,但这并不影响这个系统是合理的设计
为了让系统适配CP/AP的分类,而去改变CAP的原意,那使用CAP来描述也没有意义了
分布式系统除了CAP之外还有很多其他的细节需要考虑,如容错,延迟等过于强调CAP,容易忽略细节。
CAP的意义在于设计分布式系统时候需要考虑取舍,不是一个严格的分类方式,并且现代分布式也有更好的模型
不管你选择哪一种学习方式,我都鼓励你保持好奇心和耐心,因为这不是容易的学科。但是这是有回报的,因为你学会如果考虑取舍,进而搞清楚什么样的架构对于你的应用是最合适的。但是不管你做什么,请不要再说CP还有AP了,因为根本不合理。
思辨的看待,不要教条主义。