赞
踩
看了很多关于CAP的文章,充斥着很多晦涩难懂的词汇,甚至东拼西凑复制粘贴,越看越迷糊。
我总结了一下,有2个问题始终没有说的很清楚。
搞懂这2个问题,对CAP的理解就水到渠成了。我尝试用比较直白的语言结合图片进行说明,希望对大家有帮助。
我们用转账的例子进行说明
完成整个转账操作,总共需要两步:
一致性强调数据是最新且正确的。
在上述的例子中,当步骤一执行完成,但步骤二未完成时,如果我去查询A和B最新的余额,会得到什么呢?A余额=900,B余额=1000,这明显是不正确的。也就是不满足一致性的。
那怎样才算是满足一致性呢?很简单,程序只要等待步骤一和步骤二全部执行完成后,返回最新且正确的结果即可。
注意这里说的一致性,指的是强一致性。弱一致性和最终一致性实际上可以接受一定时间内的数据不正确,不在本文讨论范围内。
可用性强调接口必须在可接受的时间内返回结果。
接口出现长时间等待、超时、报错、甚至崩溃,都是接口不可用。所谓的“高可用”就是尽量减少这些情况的发生。
所以我们要尽量减少等待,上面的例子,只需要这样改,就达到高可用了。
但是这就出现问题了,接口返回的数据不正确了,不满足一致性了。要满足高可用,就一定会导致数据不一致吗?答案是:不一定。
可用性是一个相对的概念,不同的系统有不同的可用性要求。某些系统里,等待超过5s则不满足可用性,有的系统可能超过1s就不满足了。
如果你要求1s内返回数据就是高可用。而整个转账操作只需要10ms,那么即使等待整个操作完成再返回,你仍然觉得这个接口是高可用的。
强调系统的一部分发生故障时,其他部分还可以正常运行。
说白了,就是要把系统部署在多台服务器上,也就是分布式部署。如果程序都在一个单体服务中,那出现部分故障,整个服务就挂掉了。分布式系统,通常都要满足分区容错性(不然就叫单体服务了)。
假设我们已经满足分区容错性,把步骤一和步骤二在不同的服务部署。
转账过程中,步骤一执行完成,但是步骤二挂了。此时我仍然可以查询A的余额,但是应该返回什么呢呢?900还是1000?
如果我还要满足一致性,那我必须给你返回正确的数据。
但是B服务都挂了,我们根本不知道他到底收到100元没有,不知道900还是1000才是正确的。只能等待B服务恢复再询问它,如果它收到了100,那么用户A的余额就是900,否则是1000。
但是“等待B服务恢复”,这个时间是很长的、不可接受的,也就是说不是高可用的。
相反,如果我要满足高可用。那么我就会返回一个余额(900或1000),但是我不能保证这个数据是正确的。
其实我们把三个概念都理解之后,自然就清楚为什么只能满足2个了,这里进行一个简单的总结:
如果我要满足一致性,并且高可用(CA)
表示我必须在短的时间内,得到正确的结果。这就不能允许任何部分有故障(分区容错),因为如果有部分故障,那么其他部分就会:
如果我要满足一致性,并且分区容错(CP)
那表示我的服务部署在多个节点上,还要总是返回最新且正确的数据。那我在部分节点故障时,其他部分就只有等待或请求失败,也就是说我的系统不是高可用的。
如果我要满足可用性,并且分区容错(CP)
也就是我的服务部署在多个节点,并且当部分故障时其他节点仍能快速响应。那么这个响应的结果,就不能保证是最新且正确的。也就是可能会不一致。
综上可知,一个分布式系统,必须要满足分区容错性(P),然后再在一致性(C)和可用性(A)之间选一个。
这是被广泛采用的模式。
比如redis集群:
eureka和nacos的服务注册与发现
这种模式的其实比较少。如ZooKeeper,它具有这样的特点:
没有分区容错性的模式,大多数单体服务都满足这个要求。如单机redis。
比较典型的还是单机的关系型数据库:mysql、oracle等。具有以下特点:
当然,当你把mysql和oracle做成多节点之后,你具备了分区容错性(P),那你将必须在AP或CP模式中选一个。
可以看到分布式系统其实最优先考虑的是分区容错(P),其次是可用性(A),而能够忍受一定程度的数据不一致。这对我们自己搭建分布式系统也有很大的指导意义。
作者注:我希望用更简单的语言帮助到更多开发者,文章都是原创且亲自测试过的。希望大家不吝点赞支持。另外因为是原创文章,难免有错误或疏漏,欢迎评论指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。