CAP定理[布鲁尔定理]

CAP是Consistency、Availability、Partition Tolerance的首字母,不同的资料对这三个词的解释稍有差异,例如IBM Cloud Docs/维基百科/百度百科等等,对于CAP理论的定义也发生着变化,在第一版的解释中说的是对于一个分布式计算系统而言,不可能同时满足一致性、可用性和分区容错三个设计规约;而到了第二版的解释变成在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性、可用性和分区容错三者中的两个,另一个必须被牺牲

然而从解释中不难看出,CAP理论探讨的分布式系统强调互相连接和数据共享,也就是说例如Memcache集群并不是CAP理论探讨的对象,因为不具备相互连接和数据共享的特性,而MySQL集群式CAP理论探讨的对象;CAP理论还提及了当读写操作时,也就是说它关注的是读写操作而不是分布式系统的全部功能

Consistency 一致性

第一版的解释是所有节点在同一时刻都能看到相同的数据,到了第二版解释是对某个指定的客户端而言,读操作保证能够返回最新的写操作结果,区别非常明显:

  • 第一版从节点的角度考虑问题,第二版从客户端的角度考虑问题
  • 第一版从节点拥有数据考虑而第二版从客户端读写角度考虑
  • 第一版强调节点同时拥有相同的数据,而第二版并未强调如此说法,实际上对于系统事务来说,在事务执行过程中,系统其实处于不一致的状态,不同的节点的数据并不完全一致,因此第二版强调客户端读操作能够获取最新的写结果,因为在事务执行过程中,客户端是无法读取到未提交的数据的,只有等事务提交后,客户端才能读取到事务写入的数据,而如果事务执行失败则会回滚,客户端也不会读取到事务中间写入的数据

Availability 可用性

第一版强调每个请求都能得到成功或失败的响应,到了第二版则强调非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应),区别也很明显:

  • 第一版强调了every request,第二版强调了A non-failing node,显然更加严谨,因为故障节点并不一定能得到响应,只有非故障节点这个前提存在才可能满足可用性要求
  • 第一版强调了response分为success和failure,第二版则强调reasonable response和reasonable time,并且强调了no error or timeout

Partition Tolerance 分区容错性

第一版强调尽管出现消息丢失或分区错误,但系统能够继续运行,到了第二版则强调出现网络分区后,系统能够继续“履行职责”,区别非常明显:

  • 第一版强调系统运行,但第二版强调的是在系统运行的前提下,系统仍能够履行职责
  • 第一版强调的是message loss or partial failure,第二版则直接用network partitions,第一版中说的message loss(丢包)只是网络障碍的一种,第二版直接说现象,即发生了分区现象,不管是什么原因,可能是丢包,可能是网络中断,还可能使网络拥堵,只要导致了网络分区就算在内

CAP的选择

如果说CAP只能选择两个必须放弃一个,放到分布式环境下考量,则P是必选要素,因为网络本身无法做到100%可靠,理论上分布式系统不可能选择CA架构,只能选择CP和AP架构

CP-Consistency/Partition Tolerance

为了保证一致性,当出现网络分区现象后,N1节点上的数据已经更新到了Y,但由于N1和N2之间网络中断,数据Y无法同步到N2,N2节点上的数据还是X,这时候客户端访问N2时,需要返回error,提示客户端系统发生了故障,这种处理方式违背了可用性Availability原则

AP-Availability/Partition Tolerance

为了保证可用性,当发生分区现象后,N1节点上的数据已经更新到Y,但由于N1和N2之间的复制中断,数据Y无法同步到N2,N2上的数据还是X,此时客户端访问N2时,N2将当前自己拥有的数据X返回给客户端,而实际上当前最新数据已经是Y了,无法满足一致性Consistency

CAP细节

理论的优点在于清晰简洁,易于理解,但缺点就是高度抽象化,省略了很多细节,导致在将理论应用到实践时,由于各种复杂情况,可能出现误解和偏差,CAP 理论也不例外。如果我们需要在实践中应用 CAP 理论,如果没有意识到这些关键的细节点,就可能发现方案很难落地

CAP 关注的粒度是数据 , 而不是整个系统

CAP理论的定义和解释中,用的都是system 、node这类系统级的概念,这就给很多人造成了很大的误导,认为我们在进行架构设计时,整个系统要么选择CP,要么选择 AP 。但在实际设计过程中,每个系统不可能只处理一种数据,而是包含多种类型的数据,有的数据必须选择CP ,有的数据必须选择AP,而如果我们做设计时,从整个系统的角度去选择CP还是AP,就会发现顾此失彼,无论怎么做都是有问题的

  • 以一个最简单的用户管理系统为例 ,用户管理系统包含用户账号数据(用户ID、密码)、用户信息数据(昵称、兴趣、爱好、性别、自我介绍等),通常情况下,用户账号数据会选择CP,而用户信息数据会选择AP,如果限定整个系统为CP,则不符合用户信息数据的应用场景;如果限定整个系统为AP,则又不符合用户账号数据的应用场景
  • 所以在CAP理论落地实践时,我们需要将系统内的数据按照不同的应用场景和要求进行分类,每类数据选择不同的策略(CP还是AP),而不是直接限定整个系统所有数据都是同一策略

CAP 是忽略网络延迟的

这是一个非常隐含的假设,布鲁尔在定义一致性时,并没有将延迟考虑进去。也就是说,当事务提交时,数据能够瞬间复制到所有节点。但实际情况下,从节点A复制数据到节点B, 总是需要花费一定时间的。如果是相同机房,耗费时间可能是几毫秒;如果是跨不同地点的机房,耗费的时间就可能是几十毫秒,这就意味着, CAP 理论中的C在实践中是不可能完美实现的,在数据复制的过程中,节点A和节点B的数据并 不一致

不要小看了这几毫秒或几十毫秒的不一致,技术上是无法做到分布式场景下完美的一致性的。而业务 上必须要求一致性,因此例如单个用户的余额、单个商品的库存,理论上要求选择CP而实际上CP都做不到,只能选择CA,也就是说,只能单点写入,其他节点做备份,无法做到分布式情况下多点写入需要注意的是,这并不意味着这类系统无法应用分布式架构,只是说“单个用户余额、单个商品库存”无法做分布式,但系统整体还是可以应用分布式架构的
例如,常见的将用户分区的分布式架构如下图所示 :
在这里插入图片描述
我们可以将用户id为0~100的数据存储在Node1,将用户id为101~200 的数据存储在Node2, Client根据用户id来决定访问哪个Node,对于单个用户来说,读写操作都只能在某个节点上进行;对所有用户来说,有一部分用户的读写操作在 Node1上,有一部分用户的读写操作在Node2上
这样的设计有一个很明显的问题就是某个节点故障时,这个节点上的用户就无法进行读写操作了,但站在整体上来看,这种设计可以降低节点故障时受影响的用户的数量和范围,毕竟只影响20%的用户肯定要比影响所有用户要好,这也是为什么挖掘机挖断光缆后,支付宝只有 一部分用户会出现业务异常,而不是所有用户业务异常的原因

正常运行情况下 ,不存在CP和AP的选择 ,可以同时满足CA

CAP 理论告诉我们分布式系统只能选择CP或AP,但其实这里的前提是系统发生了“分区”现象。如果系统没有发生分区现象,也就是说P不存在的时候(节点间的网络连接一切正常), 没有必要放弃C或A,应该C和A都可以保证,这就要求架构设计的时候既要考虑分区发生时选择CP还是AP ,也要考虑分区没有发生时如何保证CA

同样以用户管理系统为例,即使是实现CA ,不同的数据实现方式也可能不一样 : 用户账号数据可以采用“消息队列”的方式来实现CA ,因为消息队列可以比较好地控制实时性,但实现起来就复杂一些;而用户信息数据可以采用“数据库 同步”的方式来实现 CA,因为数据库的方式虽然在某些场景下可能延迟较高,但使用起来简单

放弃并不等于什么都不做,需要为分区恢复后做准备

CAP 理论告诉我们三者只能取两个,需要“牺牲( sacrificed )”另外一个,实际上,CAP 理论的“牺牲” 只是说在分区过程中我们无法保证C或A,但并不意味着什么都不做,因为在系统整个运行周期中,大部分时间都是正常的,发生分区现象的时间并不长

例如, 99.99%可用性(俗称4个9 )的系统, 一年运行下来, 不可用的时间只有50分钟,99.999% (俗称5个9)可用性的系统 一年运行下来,不可用的时间只有5分钟 。分区期间放弃C或A,并不意味着永远放弃C和A,我们可以在分区期间进行一些操作,从而让分区故障解决后,系统能够重新达到 CA 的状态

最典型的就是在分区期间记录一些日志,当分区故障解决后,系统根据日志进行数据恢复,使得重新达到CA状态,同样以用户管理系统为例,对于用户账号数据,假设选择了CP,则分区发生后,节点1可以继续注册新用户,节点2无法注册新用户(这里就是不符合A的原 因,因为节点2收到注册请求后会返回error),此时节点1可以将新注册但未同步到节点 2的用户记录到日志中,当分区恢复后,节点1读取日志中的记录,同步给节点2,当同步完成后,节点1和节点2就达到了同时满足CA的状态

而对于用户信息数据,假设我们选择了AP ,则分区发生后,节点1和节点2都可以修改用户信息,但两边可能修改不一样,例如,节点1和节点2都记录了未同步的爱好数据,当分区恢复后,系统按照某个规则来合并数据,也可以完全将数据冲突报告出来,由人工来选择具体应该采用哪一条

ACID/BASE

ACID

ACID 是数据库管理系统为了保证事务的正确性而提出来的一个理论, ACID 包含四个约束, 基本解释如下

  • Atomicity (原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节 。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样
  • Consistency (一致性): 在事务开始之前和事务结束以后,数据库的完整性没有被破坏
  • Isolation C 隔离性):数据库允许多个并发事务同时对数据进行读写和修改的能力。隔离性可以防止多个事务并发执行 时由于交叉执行而 导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)
  • Durability (持久性) :事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

不难看出,ACID中的A(Atomicity)和CAP中的A(Availability)意义完全不同,而 ACID中的C和CAP中的C名称虽然都是一致性,但含义也完全不一样,ACID中的C是指数据库的数据完整性,CAP中的C是指分布式节点中的数据一致性,再结合ACID的应用场景是数据库事务,CAP 关注的是分布式系统数据读写这个差异点来看,其实CAP和ACID的对比就类似

BASE

BASE是Basically Available(基本可用)、Soft State(软状态)和 Eventually Consistency(最终一致性)三个短语的缩写 , 其核心思想是即使无法做到强一致性(CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consistency)
BASE是指基本可用(Basically Available)、软状态(Soft State)、最终一致性(Eventual Consistency)

基本可用(Basically Available)

分布式系统在出现故障时,允许损失部分可用性,即保证核心可用,这里的关键词是“部分”和“核心”,具体选择哪些作为可以损失的业务,哪些是必须保证的业务,是一项有挑战的工作

软状态(Soft State)

允许系统存在中间状态,而该中间状态不会影响系统整体可用性,这里的中间状态就是CAP理论中的数据不一致。

最终一致性(Eventual Consistency)

系统中的所有数据副本经过一定时间后,最终能够达到一致的状态,这里的关键词是“ 一定时间”和“最终”,“ 一定时间”和数据的特性是强关联的,不同的数据能够容忍的不一致时间是不同的; “最终”的含义就是不管多长时间,最终还是要达到一致性的状态

BASE理论本质上是对CAP的延伸和补充,更具体地说,是对CAP中AP方案的一个补充,前面在剖析 CAP 理论时,提到了其实和BASE相关的两点:

  • CAP 理论是忽略延时的,而实际应用中延时是无法避免的,这一点就意味着完美的CP场景是不存在的,即使是几毫秒的数据复制延迟,在这几毫秒时间间隔内,系统是不符合CP要求的,因此CAP中的CP方案,实际上也是实现了最终一致性,只是“一定时间”是指几毫秒而己
  • AP 方案中牺牲一致性只是指分区期间,而不是永远放弃一致性,这一点其实就是 BASE 理论延伸的地方,分区期间牺牲一致性,但分区故障恢复后,系统应该达到最终一致性 。

综合上面的分析,ACID是数据库事务完整性的理论, CAP是分布式系统设计理论, BASE是CAP理论中AP方案的延伸

猜你喜欢

转载自blog.csdn.net/dawei_yang000000/article/details/108571243
今日推荐