CAP 指的是什么?
CAP 指的是一致性、可用性、分区容错性。
一致性(Consistency )
CAP 想说一件什么事情,它想说咱们这个分布式系统里边,比如我们有三个节点,一号、二号、三号节点,
我们现在想做一个事务,想成功都成功,想失败都失败。
或者我保存了一个值,那大家都得跟我一样。所以我们说的第一个一致性指的就是这个。
在我们分布式系统里边,比如我们这一二三号机器,假设我们都是数据库,想要保存一个数据,比如这个数字是八,那我们既然要保存八,那一号保存了八。
我们下一个请求可能要访问二号数据库,二号就也得有八,三号也得有八。
这就相当于我们一个分布式系统里边所有这个数据的备份。
比如我们准备把八号备份在三个机器里边,所有数据的这个备份在同一个时刻是否都有同样的值。
比如我一号机器,我说八成功了,那你再来访问二号信息,结果你拿的刚才数据是七,那这个就不一致了。
所以我们说的一致性就是分布式系统里面所有的数据备份在同一时刻是一样的
可用性(Availability)
还有我们的可用性,可用性就指的是我们一号机器,二号机器和三号机器。
如果有一个机器宕机了,我们整个集群还能不能响应客户端的所有操作
假设能响应,那就说明是可用的。
如果不能响应,只要有任何一个机器炸了,我们就不响应客户端的操作,说我们这个后台集群有问题,有一个机器坏了,等我们修好了。你再来操作,那这就是不可用的。
分区容错性(Partition tolerance)
分区容错指的就是我们一号机器,二号机器,三号机器。由于它们部署在不同节点。
它们之间通信肯定要使用这个网络,网络肯定会出现的一些通信失败、错误问题。
只要通信失败,就说我们这个分区发生了这个错误,我们接下来该怎么办?
面临的问题
但是我们现在能发现一件事,就是我们这个一致性、可用性、分区容错性,这三个不能三者兼顾,为什么?
我们来举一个例子,假设一致性
一、二、三、三个机器都想要保存八号数据。
我们一个请求过来,让它三个备份节点,同时都要把八号数据保存起来。
所以如果我们想要满足一致性c ,那我们现在三个机器全部都保存好了。
那么接下来在可用性和分区容错二选一,怎么叫分区容错二选一?
假设我们不是由于节点故障,而是由于通信故障,我们一号跟三号机器的网线断了。
保存数据肯定只给某一个机器发了请求,我给一号机器发了八请求。
然后,一号机器让二号机器同步了一下,二号也保存了八,结果让三号机器同步的时候,由于网线断了,它死活连不到三号机器。
那此时就发生了分区错误,我们这个网络出错了,就是我们分区容错。
我们分区错误以后,接下来我们就考虑。
我们能不能满足可用性?假设我们还让它满足可用性。
行,我们让它三个机器都能用,那下一个客户端的请求。
比如我们负载均衡。去三号里边读数据了,但是由于三号通信故障,把一号的数据没同步过来。那它读到的数据不就不一样了吗?
所以你一满足可用性,你发现又不一致了。
所以你想要满足一致,那你就必须让三号机器不能访问,那它不能访问,相当于我们就不可用了。
所以我们说的这个一致性和可用性只能二选一。
在分布式系统里边,我们永远都要满足分区容错。
因为我们这个网络肯定会出现问题,所以我们这个分区容错性分区出错了。我们一定要想办法解决,但怎么想办法解决?
那就二选一,那我们到底是要满足一致还是满足可用。
如果满足可用,让它们能去访问,那相当于下一个人能访问三号机器。那它访问到的就是不一致的数据,那相当于你就容忍了这个业务能访问到不一致的数据。
我们前边的人都是八,接下来这个人访问却变成了七。
但如果我们想要满足一致,我们一定让它访问任何一个节点。那都是八。那这样的话我们就不能让整个集群可用。如果我们让整个集群可用了,那发给一号二号的请求读出来是八,没问题。但是发给三号的请求读出来是七,会不一致的。
所以我们必须把所有的集群全部禁掉。
你说你给一号机器保存了八,然后。只要三号机器没同步,我就给你不响应,说我这个八保存成功了,我就告诉你保存失败了,要不然我告诉你保存成功了,你还跑三号机器一拿,结果还拿出来了。
这就是我们说的一致、可用必须二选一,而 p 我们是必须要选择的。所以我们这个 CA 二选一,
所以我们最终我们的分布式系统里边。要么是一个 CP 系统,要么是一个 AP 系统,CA 系统做不到,
因为你没办法保证你的网线不断,网络不中断,除非你是单台机器,单台机器自己连自己机器的数据库,自己连自己的 redis,所有的数据库、redis 都装在一台机器里边。那可以来考虑 CA。所以这个 c 其实就是本地。
所以我们不可能有 CA,只有 CAP 和 AP,这就是我们说的 CAP 定理。
同样的映射到我们的业务里边。我们分布式系统都得满足这个定理。
但是我们现在来考虑,如果我们来说 AP,我们分区错误了,我们让它可用读到的不一致就不一致。三个节点你突然去读三号节点数据跟一二不一样,就不一样的。我们满足 AP 没得说,
关键如果我们想要满足 CP,我们在分布式系统里边,想要保证它一致性。即使网络出错了,我们都能一致。那怎么一致?
我们牺牲可用,牺牲可用是一个方面。第二方面我们能不能通过什么算法能保证它们之间的一致?
我们在分布式系统里边一般会有一些一致性算法,典型的代表,比如说 raft 算法,还有我们的 pencil 算法等等等等。
Raft 算法
保证 CP
BASE 理论
在我们整个互联网系统,我们这个大型微服务,我们拆分出了好多微服务。
然后集群规模非常大,肯定会存在网络故障,假设有几个机器可能就访问不通了,这个网络就中断了,或者有几个机器宕机了。
那么节点故障网络故障这都是常态。但是无论是网络怎么故障,节点怎么故障。我们肯定要保证我们整个集群系统是一个可用状态,不应该出现。有两三个服务出现问题了,或者网络不通了,然后导致我们整个商城不可用了。
所以我们最终都是想要保证我们的服务可用性能达到百分之九十九点九九九九这个效果。
最终我们还是来选择使用 AP,也就是分区容错的情况下,我们保证 A 而舍弃 C,
这里所说的这个 C 就是强一致。我们不要求数据立马同步一致、成功就是成功、不成功就是不成功。我们要舍弃这个强一致
但是就算舍弃强一致,我们也得保持一致,
以我们这个订单为例
我们开始下单,然后去仓储服务减库存,库存已经减了。然后在订单服务保存订单,订单也存了。
然后接下来我们去账户服务扣减积分,然后这个积分扣失败了,假设我们订单是调的扣减积分,订单回滚了,但是已经扣了的库存他没法回滚,因为扣库存是一个远程方法,
但不管回不回滚,我们最终要做的就是发现我们的扣库存这个方法你没法回滚,但是你已经扣了,那过上一段时间以后,我发现你扣的这个库存没什么用,我再给你加回来。
所以分布式系统,在我们这个业务里边,我们要保证数据业务前后状态是一致的。
此时有人提出了 BASE 理论