1.什么是CAP
1.1CAP简介:
在分布式系统中,CAP是指一组原则,它们描述了在网络分区(Partition)时,分布式系统能够提供的保证。CAP代表Consistency(一致性)、Availability(可用性)和Partition Tolerance(分区容错性)。
一致性(Consistency ):
简单来说,写入数据到分布式系统的某一个节点后,操作会立刻反应到整个分布式系统上。即任何时刻从任意一个节点读取的数据都必须是一样的。
要实现一致性 ,那么需要保证:当在分布式系统更新一个节点的数据时候,分布式系统会立马 把这个数据同步到所有 的节点上。要么所有节点都更新数据,要么都不更新。始终保持所有节点数据一致。
并且在这个数据同步期间,分布式系统不能对外提供服务,否则会违背一致性(因为可能会访问到尚未同步的节点,此时读到的数据就不一致了)。
举个例子,当对节点 A 执行操作 set x = 1; 之后,x 的新值会立刻同步到所有的节点上,保证所有的节点上 x 值都被更新为 1。
可用性(Availability):
即任何时刻对于分布式系统节点的访问都会返回成功 的结果,而不会是超时 或者失败 。可用性强调的是一定能读到数据 ,至于读取到的数据是新值 还是旧值都不影响,但一定要能成功访问。
分区容错性(Partition-tolerance):
分区容错性 (Partition Tolerance)是指分布式系统在面对网络分区(Network Partition)时仍然能够正常运行的能力。网络分区是指系统中的节点之间无法互相通信或通信延迟非常高的情况。
在分布式系统中,由于网络的不可靠性和不稳定性,网络分区是常见的情况。例如,一个由多个节点组成的分布式系统可能由于网络故障、服务器故障或网络拥塞等原因导致节点之间无法彼此通信。
分区容错性的目标是使分布式系统能够在网络分区的情况下仍然保持运行和提供服务。这意味着即使网络分区发生,系统的各个节点仍然能够正常处理请求、进行数据读写操作,并向用户提供结果。
1.2为什么说 CAP 不能同时满足?
我们都听过分布式系统中 CAP 是无法同时满足的,但是很多时候都是只有一个模糊概念,所以我就从一个简单例子说起吧。
有一个很简单的程序,就存了几个键值对。我们在多台机器上都部署这个程序,整体对外提供服务,这就成了一个简单的分布式系统 。每一个运行的程序称为一个节点,如图所示:
此时,某个客户端 Client1 连接了节点 A ,向节点 A 发起请求: SET a = 999;
然后某个客户端 Client2 连接了节点 B ,发送请求:GET a; 立马读取 a 的值。
先假设现在我们要满足 Consistency 一致性 。前面提过,需要保证:当在分布式系统更新一个节点的数据时候,分布式系统会立马把这个数据同步到所有的节点上。要么所有节点都更新数据,要么都不更新。始终保持所有节点数据一致。
怎么保证这一点呢?有两个方案:
方案一:数据全部都只存放在一个节点上。其他节点全部从这个节点上读取数据。
很容易理解,所有数据都在一个节点 上,那么就根本不需要 "把数据同步到其他节点 " 这一步操作了,其他所有节点读写数据请求都会被转发 到这个节点上来执行。所以它一定满足 Consistency 一致性。
在这个例子中即只有 节点 A 保存了所有数据,其他节点数据全是空的,Client2 的请求会被转发 到节点 A 上,因此得到的 a 都是 999 。一致性得到保证。
另外,由于只有一份数据,没有数据同步 这一步骤,因此分布式系统在任何时间都是能对外提供服务的。下一个请求能够立马得到成功 的响应。所以 Availability 可用性 也是满足的。
然而,这个系统满足 Partition-tolerance 分区容错性 吗? 遗憾的是并不满足:
很简单,因为数据全部存在节点 A 上。假设节点 B 与节点 A 的网络通信因为某种原因中断了(这是很有可能的),此时发生分区 。节点 B 就无法对外提供服务了,因为他无法从节点 A 拿到数据 。这违背了分区容错性的定义。所以不满足分区容错性。
综上,这个系统满足 Consistency 一致性 和 Availability 可用性 ,但是不满足 Partition-tolerance 分区容错性 。这属于 CA。
方案二:每个节点都存放数据。
在这种方案下,要保证一致性 ,那么必须要将数据修改立刻同步 到每一个节点。然而同步数据总得需要时间,在这个时间段内,分布式系统不能对外响应,否则会违背一致性。
当在节点 A 执行 SET a = 999 的操作后,节点 A 需要将这个操作同步到其他的节点上,保证数据的一致性。
Consistency 一致性 满足之后,每个节点都是完全相同 的数据备份。此时就算某个节点 A 与其他节点的通信中断,此时产生了两个分区 单独的节点A 是一个分区, 其他所有节点 是另外一个分区。但是这两个分区都有完整的数据 ,因此都可以对外提供服务。也就是说满足了 Partition-tolerance 分区容错性。
那可用性满足吗?并不。
在节点数据同步的过程中,整个分布式系统不能对外提供服务。因此在这个过程中的请求都无法得到响应,所以 Availability 可用性 无法满足 。Client2 的请求会超时,而不是立马返回成功,因此可用性不成立。
综上,这个属于 CP。
另外,假设我不选择 Consistency 一致性 的时候,能同时满足 Availability 可用性 和 Partition-tolerance 分区容错性 吗?
可以。 因为不需要满足一致性 了,实际上每个节点的数据都有自己的副本,但是这些副本的值并不一定完全相同,因为没有数据同步 。对于 Client1 来说 GET a 得到的是 999 . 而对于 Client2 来说 GET a 是 1。
此时就算发生网络分区 ,每个节点都还是能对外服务的。所以满足 Partition-tolerance 分区容错性。
而且任一时刻的请求也能正常得到响应,因为没有数据同步的过程,自然任何时候都能处理请求了,所以也满足 Availability 可用性。 这个就是 AP。
至此,我们已经可以得到结论。分布式系统中 CAP 三者是不能完全同时满足的,只能够3选2了。。
通常,在分布式系统中 Partition-tolerance 分区容错性 是我们不得不选择的。 很容易理解,不选择分区容错性,就等于数据只放在一个节点A上。那这个分布式系统的意义好像也不大,搞来搞去鸡蛋还是放在一个篮子里了。这个节点 A一旦挂了整个系统毫无疑问直接挂掉,这对生产环境来说通常是难以接受的。
2.如何选择CP还是AP
所以,既然选择了 P,那剩下就要在 A 和 C 之间进行一个抉择了。两个都重要,那怎么办,折中 好了!于是又出现了经典的 BASE 理论。
BASE 理论是由 eBay 的架构师提出的一套经典的分布式理论 。 它包涵以下三点 :
Basically Avaiilability(BA) 基本可用性:不像 CAP 里面要求立即可用,BA 强调的是 基本可用。例如在数据同步期间,延长用户等待时间(即等待数据同步完)再向用户返回,或是提示用户稍后重试等等。由于这个特性,给了我们一点缓冲时间去进行数据同步。
Soft State(S)软状态:软状态允许节点数据存在中间状态,即分布式系统的数据同步操作还在进行中,允许有一定的时延。
Eventually Consistent(E)最终一致性: 即经过一定时间后数据最终会完全同步,所有节点数据最终会保持一致。
可以看到,BASE 理论像是对 C一致性 和 A可用性 的一种折中,它尽量向两者都靠近。至于到底怎么做,那就需要根据业务自身特点来选择。
CAP 里面的一致性是强一致性 ,而这里是最终一致性。如何理解两者区别呢:
举个例子,电商网站展示商品列表,某个用户同时用手机和电脑在浏览商品页面,完全有可能连接到两个不同的节点上 A 和 B上。
此时上架一批新商品,数据更新到节点 A 中。用户在手机端可以立马查到这些新的商品信息(手机端连接的是节点A),电脑端需要经过 5s 之后才能查询到新的商品(假设 5 s 用于节点 A 数据同步到 B),不过电脑端仍然能查询到旧的商品数据,这对用户来说是完全可以接受的。这就是 最终一致性 方案。
相反,如果要满足强一致性 。需要保证用户在手机和电脑上看到的商品信息是完全一致的。 那么上新之后马上同步数据到节点 B上。 并且在此期间系统暂时处于不可用状态,因为你不能让用户查到不一致的数据。显然这对用户来说是较难接收的。
因此这种业务场景下我们更应该选择最终一致性 ,而不是强一致性。
不过,在一些对数据敏感的场景下,比如在网银支付的场景中,一个用户进行转账的时候,数据更新如果不满足强一致性 的话,在数据等待同步期间用户看到的数据不一致,这时候就会导致很严重的问题,这个时候我们不得不牺牲一些可用性,保证强一致性。
总之适合业务场景的方案才是最好的方案。