一:CAP基础

原文连接

CAP

网络分区

在一个分布式系统中,各个节点通过网络连接在一起。由于网络不可达,节点间就出现了网络分区,网络分区有哪些影响呢?

  • 如果数据仅存在于少量节点,当这些节点网络不可达后,这些数据就无法被访问了。

一致性

一致性变化

什么是数据一致性?一致性值当数据发生变化时,数据会按照预定地规则,一起发生变化,从状态变化到另一个一致的状态。例如:账户转入、转出一致;多个数据副本间的一致。

数据什么时候会发生变化?

仅当包含数据的服务收到数据更新请求时,数据才会发生变化。更新请求可以分为三类:增删改。即数据在发生写请求的时候会产生变化。

既然写请求后数据发生了变化,通过什么方式、何时去判断这个变化是否发生?是否达到了预期的一致?

判断数据发生一致性变化需要通过读请求来判断,那么读请求的判断依据是什么呢?

假设,将数据存储在多个不同的位置,每个节点都包含一部分需要被改变的数据,经过写请求后,各个节点的数据都发生了变化,然后通过读请求,从各个节点都可以读取到相应的变化,那么这次数据修改称为:数据发生了一致性变化。例如:

  • 将数据拷贝为多个副本,用户从任意节点都可以读取到一致的数据。

  • 两个账户系统,数据分别存储在各自的数据库,A用户转账给B用户后,A用户可以看到自己的扣减金额,B账户可以看到自己账户的增加金额。

v2-34031bde4b30adfe7458997713ea08f8_1440w

系统总会发生异常,如何保证系统异常后,数据依旧是一致的?系统会发生哪些异常?它们是如何导致数据不一致的?

当系统异常,导致内部数据无法发生一致性变化。此时读请求从不同节点或不同时间,可以拿到不一致的数据。(为了保持一致性,可以不返回任何数据--这是保证一致性的方案之一,但也意味着现在系统不可用)

v2-0204ccbd9f2db25f214975123c6b43fc_1440w

可用性

可用性在 CAP 里就是对结果的要求。它要求系统内的节点们接收到了无论是写请求还是读请求,都要能处理并给回响应结果。只是它有两点必须满足的条件:

  • 条件 1:返回结果必须在合理的时间以内,这个合理的时间是根据业务来定的。业务说必须 100 毫秒内返回,合理的时间就是 100 毫秒,需要 1 秒内返回,那就是 1 秒,如果业务定的 100 毫秒,结果却在 1 秒才返回,那么这个系统就不满足可用性。

  • 条件 2:需要系统内能正常接收请求的所有节点都返回结果。这包含了两重含义:

    • 如果节点不能正常接收请求了,比如宕机了,系统崩溃了,而其他节点依然能正常接收请求,那么,我们说系统依然是可用的,也就是说,部分宕机没事儿,不影响可用性指标。

    • 如果节点能正常接收请求,但是发现节点内部数据有问题,那么也必须返回结果,哪怕返回的结果是有问题的。比如:

      • 系统有两个节点,其中有一个节点数据是三天前的,另一个节点是两分钟前的,如果,一个读请求跑到了包含了三天前数据的那个节点上,抱歉,这个节点不能拒绝,必须返回这个三天前的数据,即使它可能不太合理。

      • v2-b0a5d7c2b86ea7e37a0db164c9f157ff_1440w

分区容忍性

分区:

分布式的存储系统会有很多的节点,这些节点都是通过网络进行通信。而网络是不可靠的,当节点和节点之间的通信出现了问题,此时,就称当前的分布式存储系统出现了分区。(但是,值得一提的是,分区并不一定是由网络故障引起的,也可能是因为机器故障。)

v2-b4390ebafc1e914f2b8949eaefa2bcb3_1440w

分区容忍性:

如果出现了分区问题,我们的分布式存储系统还需要继续运行。不能因为出现了分区问题,整个分布式节点全部就熄火了,罢工了,不做事情了。

v2-a57436c47f10d12dbb53d288bbed6b92_1440w

CAP 怎么选择

在以分布式存系统为限定条件的 CAP 世界里,P 是早已经确定的答案,P 是必须的。为什么呢:如果不保证分区容错性,当分区发生时,整个系统将瘫痪,无法对外提供服务。

所以我们需要考虑的是:当分区发生后,系统如何才能继续对外提供服务,和提供什么样的服务。例如:

  • 是舍弃数据的一致性,来提供该可用的服务;

  • 还是为了保证数据一致性,降低服务的可用性;

  • 或者说保证适当的可用性,尽量保证数据一致性(在等待最大容忍时间后,数据依旧没有达到一致,这是即使数据不一致也得向用户返回数据)。

因为,在分布式系统内,P 是必然的发生的,不选 P,一旦发生分区错误,整个分布式系统就完全无法使用了,这是不符合实际需要的。所以,对于分布式系统,我们只能能考虑当发生分区错误时,如何选择一致性和可用性。而根据一致性和可用性的选择不同,开源的分布式系统往往又被分为 CP 系统和 AP 系统。

  • CP 系统:当一套系统在发生分区故障后,客户端的任何请求都被卡死或者超时,但是,系统的每个节点总是会返回一致的数据,则这套系统就是 CP 系统,经典的比如 Zookeeper。

  • AP 系统:如果一套系统发生分区故障后,客户端依然可以访问系统,但是获取的数据有的是新的数据,有的还是老数据,那么这套系统就是 AP 系统,经典的比如 Eureka。

其实 CAP 定理本质很简单,它就是一种分布式系统设计的不同理念概括,包括它说的一致性,可用性和分区容错性。这就类似一个大学的校训,是极度概念化的东西。

大白话来形容下 CAP 吧,CAP 就是告诉程序员们当分布式系统出现内部问题了,你要做两种选择:

  • 要么迁就外部服务,像外包公司。

  • 要么让外部服务迁就你,像银行。

迁就外部服务就是我们不能因为我们自己的问题让外部服务的业务运行受到影响,所以要优先可用性。而让外部服务迁就我们,就要优先一致性。

误解一:分布式系统因为 CAP 定理放弃了 C 或者 A 中的其中一个

P 这种问题发生的概率非常低,所以:

当没有出现分区问题的时候,系统就应该有完美的数据一致性和可用性。(你什么时候见过一个系统,当内部没有问题的时候,会经常让外部请求卡一下的?要么就冷不丁的提供陈旧的老数据?那还能叫系统吗?)

误解二:C 和 A 之间的选择是针对整个分布式系统的,只能整体考虑 C 和 A 之间的选择

这个理解也是不对的。当分区发生的时候,其实对一致性和可用性的抉择是局部性的,而不是针对整个系统的。可能是在一些子系统做一些抉择,甚至很可能只需要对某个事件或者数据,做一致性和可用性的抉择而已。比如:

  • 当我们做一套支付系统的时候,会员的财务相关像账户余额,账务流水是必须强一致性的。这时候,你就要考虑选 C。(仅仅是当系统出现错误的时候,去放弃可用性,不是任何时候都需要)

  • 但是,会员的名字,会员的支付设置就不必考虑强一致性,可以选择可用性 A。(即使系统发生了分区,也可以立马相应)

误解三:CAP 的三个特性只有是和否两种极端选择,而不是一个范围

这种二元性的理解更是极其误导人。就像去银行去取钱,而且要新的。例如:我向系统写入一条数据并读取它,如果系统运行良好,我可以立马获取到数据(CA并存);但不幸的是,系统发生了分区,数据还没有同步到到每一个节点,这时候我可以等,但总得有个限度吧,100ms后依旧没有同步完成,那要求系统立马返回数据,即使数据是错的,此时就是为了一定限度的可用性,放弃一致性;但是数据很重要,无法容忍不一致,那么系统就可能无限期等下去,这时候就是为了C,放弃P。但更多时候,我们并不是非此即彼,我们可以设定一个最大等待时间,来保证可用性,尽量确保一致性。

posted @ 2021-07-05 15:51  code汤  阅读(92)  评论(0)    收藏  举报