在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)这三个基本需求,最多只能同时满足其中的2个。
Consistency(一致性):指数据在多个副本之间能够保持一致的特性(严格的一致性)。
Availability(可用性):指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据)。
Partition tolerance(分区容错性):分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障。
分区释义:在分布式系统中,不同的节点分布在不同的子网络中,由于一些特殊的原因,这些子节点之间出现了网络不通的状态,但他们的内部子网络是正常的。从而导致了整个系统的环境被切分成了若干个孤立的区域。
假设现在有两个网络节点 Node1(应用程序A和数据库实例M1)和 Node2(应用程序A和数据库实例M1),二者构成一个分布式应用。
1、我们首先分析一下假设满足CAP理论中其中一条,会是什么场景:
满足一致性Node1和Node2中的数据是一样的,及M1和M2保存的数据是一致的。
满足可用性用户不管是访问到哪个应用程序(要么是A,要么是B),都能得到响应(虽然数据不一定一样)。
满足分区容错性Node1和Node2任意一台节点宕机(是不可完全避免的),获取发生网络分区,彼此之间互不影响,还能够继续使用,也就是还能够继续满足可用性。
2、接下来再分析一下该分布式应用正常运行的情况,所谓正常运行,我们就假如M1中数据会经过一定的手段同步到M2,这样用户通过应用程序A或者B都能得到准确的数据。那么在正常运行中该分布式应用套用到CAP理论中:
一致性Node1和Node2的数据M1和M2之间的数据是否完全一样。
可用性Node1和Node2的对用户的请求能否做出正常的响应。
分区容错性Node1和Node2之间的网络是否互通或者说服务器状态是否正常。
3、现在假设一种极端情况,Node1和Node2之间的网络断开了,我们要支持这种网络异常。相当于要满足分区容错性,能不能同时满足一致性和可用性呢?还是说要对他们进行取舍?
现在假设一个用户通过Node1的应用程序A将M1中的数据做了更新,但由于网络原因,M1中的更新未能同步到M2中去,这时另一个用户请求时,应用程序B没办法立即给用户返回最新的数据,这时该怎么取舍?
牺牲数据一致性,保证可用性响应旧数据给用户。
牺牲可用性,保证数据一致性阻塞等待,直到网络连接恢复,数据更新操作同步完成之后,再给用户响应最新的数据。
经过上述分析可知,要满足分区容错性的分布式系统,只能在一致性和可用性两者中,选择其中一个。
如果不要求P(不允许分区),则C(强一致性)和A(可用性)是可以保证的。但其实分区不是你想不想的问题,而是始终会存在,因此CA的系统更多的是允许分区后各子系统依然保持CA。
如果不要求A(可用),相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。
最终一致性
对于多数大型互联网应用的场景,主机众多、部署分散。而且现在的集群规模越来越大,所以节点故障、网络故障是常态。这种应用一般要保证服务可用性达到N个9,即保证P和A,只有舍弃C,也就是退而求其次保证最终一致性。但可能会影响用户体验。
到底能不能选择 CA
在分布式系统中,网络无法100%可靠,分区其实是一个必然现象,如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求,但是 A 又不允许,所以分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。