前言对于CAP的理解我也看了很多书,也看了很多同事的博文。基本上每个人的理解都不一样,Brewer教授的定义也不一样。太简单了,没有具体的描述和场景案例分析。因此,我参考了一些资料,整理了一篇文章与大家分享。标题是为了理解正确而写的,可能有些地方不是绝对正确或者有歧义,但希望在和大家分享讨论后达到最终的正确。CAP定理,又称布鲁尔定理,是埃里克·布鲁尔教授于2000年提出的一个猜想,指出对于分布式系统,不可能同时满足以下三个条件:要点:一致性(consistency):所有节点同时看到相同的数据。(所有节点同时拥有相同的数据)可用性(availability):保证每个请求都会收到关于成功或失败的响应。(保证无论成功或失败,每个请求都有响应)分区容忍(separationtolerance):即使系统的任何一部分丢失或发生故障,系统仍继续运行。(系统中任何信息的丢失或故障都不会影响系统的继续运行)很多书籍和文章引用了RobertGreiner在2014年8月写的一篇博文http://robertgreiner.com/2014/08/cap-定理重访/。RobertGreiner的定义比看Brewer教授傻眼的定义更容易理解。原始定义:在分布式系统(共享数据的互连节点的集合。)中,您只能在写/读对中拥有以下三种保证中的两种:一致性、可用性和分区容错性-其中之一必须是牺牲了。翻译:在分布式系统(相互连接并共享数据的节点集合)中,当涉及到读写操作时,只能保证Consistence,Availability,PartitionTolerance)三者中的一个,其他必须被牺牲。关键词:互连节点(interconnectednodes),共享数据(shareddata),一个写/读对(read/write)从上面这段话,有几个,也就是说,当我们讲CAP定理的时候,我们有在数据读写、数据共享、节点互联的前提下,选择以上三者中的第二者,也建议大家不要花时间和精力同时满足这三者。比如web集群和memcached集群不属于讨论的范围。Web集群只是资源在不同节点上的复制和分布。但是,节点之间没有互连,没有数据共享(sessionid,内存缓存)。Memcached集群数据存储通过客户端实现哈希一致性,但集群节点之间不互联,不存在数据共享。一般来说,CAP定理并未讨论分布式系统的所有功能。一致性(Consistency)原文:读取保证返回给定客户端的最新写入。翻译:对于指定的客户端,读操作保证返回最好的写操作结果关键字:agivenclient(指定客户端)。这里的一致性和我们平时理解的ACID的一致性有点不一样。ACID的一致性关系到数据库的数据完整性。上面的定义并不是说所有的节点都必须同时拥有相同的数据,而是重点在客户端。如果有这样一种场景,你在ATM(客户端)的银行卡里存了500元,马上在ATM上发起余额查询,添加500元后会显示余额,然后我们就可以取出这500元了。查询余额读操作可以写入后立即从主库读取,也可以写入后一定时间后从从库读取(中间不写入)。可用性(Availability)原文:非故障节点会在合理的时间内(无错误或超时)返回合理的响应。翻译:非故障节点将在合理的时间内返回合理的响应(不是错误或超时)。关键词:非故障节点(non-faultynode),合理响应(reasonableresponse)这里的可用性和我们通常理解的高可用性有点不一样。高可用性是指系统不间断地执行其功能的能力。失败的节点不可用,因为请求结果要么错误要么超时。一个合理的响应不会说它是成功还是失败,但响应应该对它是成功还是失败有一个准确的描述。比如我们在读取sqlserver集群的某个从库时,同步是需要时间的,读取到的数据可能不是最新的数据,但是是合理的响应。分区容忍度(Partitiontolerance)原文:当网络分区发生时,系统会继续运行。翻译:当发生网络分区时,系统会继续正常运行在一个一主两从的集群中,某一天一个从节点因为网络故障不可用,但是另外一主一从仍然可以正常运行,那么我们认为它具有分区容错性。CA-sacrificingpartitionfaulttolerance作为分布式系统,分区总会出现(50分钟2年一次还是10分钟1年3次?),所以相信大部分关于CAP的讨论都是建立在P,假设我们牺牲P,此时由于网络故障导致节点分区不可用。此时请求响应error超时,与availability的定义冲突。但是,如果我们假设大部分时间分区不存在,那么在读/写单个节点时就没有必要在C和A之间做出选择。但是上面说分区总是会发生,这不是自相矛盾,或者是取舍。如果一年内99.99%时间正常,0.01%(52.56分钟)不可用时间不可用,如果这个时间在业务受理范围内,或者只影响某个区域(华南、华北、华中)中国?),那么CA也是可选的。PC牺牲可用性最典型的案例是RDBMS集群和Redis集群,它们都使用主从复制来实现读写分离。如果两者都是建立一主多从的集群,在master节点上写入数据,为了保证后续的读操作获取的是最新的数据(一致性),本次读操作仍然会请求master节点(复杂读写分离)重点是从库同步不及时,导致业务异常。为保证业务正常,先写后读会请求主库),某个从节点挂了,但是只要主节点和其他从节点还在正常运行,分区容错是满足的性别。但是当master节点因为网络故障导致写操作出错或者超时,那么系统就会不可用(牺牲可用性)。这时候可以引入其他的功能和机制,比如Redis哨兵模式和故障转移功能。牺牲PA一致性的最典型案例是Cassanda集群和Riak集群。这种类型的分布式数据库可以被任意节点写入和任意节点读取。当它作为一个集群出现时,无论写入哪个节点,这个节点的数据都会同步到其他节点。因为这种同步方式,所以读取数据时只访问一个节点就可以了(如果你喜欢随意访问,就不拦你),但是因为其他节点的数据同步,数据可能不会被***(牺牲)一致性)。如果由于网络异常导致当前节点不可用(无论读/写),可以转移访问节点(可用性)。另外,这里说的牺牲一致性并不意味着放弃一致性,PA选择的是最终一致性(系统中的所有数据副本经过一段时间的同步后最终可以达到一致状态)。“牺牲”二字并不代表非此即彼的选择,可以根据子系统和模块(如PA与PC、CA与PC)的设计进行混搭。本文对CAP定理做一个简单的描述。我参考了一些书籍和文章,加上自己的理解。我希望我能和你分享。如果您有不同的建议和意见,包括文章描述中的错误,请在下方评论中指出。I将在适当的时候进行修正。
