分布式事务一

CAP和BASE理论

Posted by Jason Lee on 2022-04-01

基础理论

CAP 理论

CAP 定理(Consistency、Availability、Partition Tolerance Theorem),也称为 Brewer 定理,起源于在 2000 年 7 月,是加州大学伯克利分校的 Eric Brewer 教授于“ACM 分布式计算原理研讨会(PODC)”上提出的一个猜想。两年之后,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 以严谨的数学推理证明了 CAP 猜想。自此,CAP 正式从猜想变为分布式计算领域所公认的著名定理。这个定理里描述了一个分布式的系统中,涉及共享数据问题时,以下三个特性最多只能同时满足其中两个:

CAP理论的取舍

上述就是比较著名的CAP理论中的CAP的概念。当然,在理想的情况下,CAP的特性都是分布式系统所要追求的方向,但实时是,在分布式的环境下CAP不可能同时满足。

CAP的定义

布鲁尔在提出CAP猜想的时候,并没有详细定义Consistency、Availability、Partition Tolerance 三个单词的明确含义,因此如果初学者去查询CAP定义的时候会感到比较困惑,因为不同的资料对CAP的详细定义有一些细微的差别。

IBM Cloud Docs:

Consistency,where all nodes see the same data at the same time.
Availability,which guarantees that every request receives a response about whether it succeeded or failed.
Partition tolerance,where the system continues to operate even if any one part of the system is lost or fails.

维基百科:

Consistency:Every read receivesthe most recent write or an error Availability:Every request receives a(non-error)response-without guarantee that it contains the most recent write Partition tolerance:The system continues to operate despite an arbitrary number of messages being dropped(or delayed)by the network between nodes

Silverback:

Consistency:all nodes have access to the same data simultaneously Availability:a promise that every request receives a response,at minimum whether the request succeeded or failed Partition tolerance:the system will continue to work even if some arbitrary node goes offline or can’t communicate

为了更好地解释CAP理论,下面挑选了Robert Greiner的文章作为参考基础。有趣的是,Robert Greiner对CAP的理解也经历了一个过程,他写了两篇文章来阐述CAP理论,第一篇被标记为“outdated”(有一些中文翻译文章正好参考了第一篇),下面将对比前后两篇解释的差异点,通过对比帮助你更加深入地理解CAP理论。

CAP定理

版本 英文定义 翻译
第一版 any distributed system cannot guaranty C,A,and P simultaneously。 对于一个分布式计算系统,不可能同时满足一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三个设计约束。
第二版 in a distributed system (a collection of interconnected nodes that share data.),you can only have two out of the following three guarantees across a write/read pair:Consistency,Availability,and Partition Tolerance-one of them must be sacrificed。 在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance) 三者中的两个,另外一个必须被牺牲。
  • (1)第二版定义了什么才是CAP理论探讨的分布式系统,强调了两点:interconnected 和share data,为何要强调这两点呢?因为分布式系统并不一定会互联和共享数据。最简单的例如Memcache的集群,相互之间就没有连接和共享数据,因此Memcache集群这类分布式系统就不符合CAP理论探讨的对象;而MySQL集群就是互联和进行数据复制的,因此是CAP理论探讨的对象。
  • (2)第二版强调了 write/read pair,这点其实和第1条差异点是一脉相承的。也就是说,CAP关注的是对数据的读写操作,而不是分布式系统的所有功能。例如,ZooKeeper的选举机制就不是CAP探讨的对象。

相比来说,第二版的定义更加精确。虽然第二版的定义和解释更加严谨,但内容相比第一版来说更加难记一些,所以现在大部分技术人员谈论CAP理论时,更多还是按照第一版的定义和解释来说的,因为第一版虽然不严谨,但非常简单和容易记住。

一致性

  • 一致性(Consistency):直观的解释为:代表数据在任何时刻、任何分布式节点中所看到的都是符合预期的。我来解释一下。也就是说,当一个数据状态改变命令(这里可以理解为写操作,写操作可以有任何方式,比如说一个客户端请求,一个数据库的更新等等)发生并且成功后,系统对外承诺改变化已经生效并且改数据对外的任何状态都是改变完成后的状态。这里的一致性强调的是数据状态。

官方解释有两个版本:

版本 英文定义 翻译
第一版 All nodes see the same data at the same time。 所有节点在同一时刻都能看到相同的数据。
第二版 A read is guaranteed to returm the most recent write for a given client 对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。

第一版解释和第二版解释的主要差异点表现在以下几个方面:

  • 第一版从节点node的角度描述,第二版从客户端client的角度描述。相比来说,第二版更加符合我们观察和评估系统的方式,即站在客户端的角度来观察系统的行为和特征。
  • 第一版的关键词是see,第二版的关键词是read。第一版解释中的see,其实并不确切,因为节点node是拥有数据而不是看到数据,即使要描述也是用have:第二版从客户端client的读写角度来描述一致性,定义更加精确。
  • 第一版强调同一时刻拥有相同数据(same time+same data),第二版并没有强调这点。
    这就意味着实际上对于节点来说,可能同一时刻拥有不同数据(same tim +differentdata),这和我们通常理解的一致性是有差异的,为何做这样的改动呢?其实在第一版的详细解释中已经提到了,具体内容如下:

A system has consistency if a transaction starts with the system in a consistent state, and ends with the system in a consistent state. In this model,a system can (and does) shift into an inconsistent state during a transaction,but the entire transaction gets rolled back if there is anerror during any stage in the process.

参考上述的解释,对于系统执行事务来说,在事务执行过程中,系统其实处于一个不一致的状态,不同的节点的数据并不完全一致。因此第一版的解释“All nodes see the same data at the same time”是不严谨的,而第二版强调client 读操作能够获取最新的写结果就没有问题。因为事务在执行过程中,client是无法读取到未提交的数据的,只有等到事务提交后,client才能读取到事务写入的数据,而如果事务失败则会进行回滚,client也不会读取到事务中间写入的数据。

可用性

  • 可用性(Availability):直观解释:代表系统不间断地提供服务的能力

官方两个版本的解释:

版本 英文定义 翻译
第一版 Every request gets a response on success/failure. 每个请求都能得到成功或失败的响应。
第二版 A non-failing node will retum a reasonable response within a reasonable amount of time (no error or timeout). 非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。

简单理解为:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。理解可用性要先理解与其密切相关两个指标:可靠性(Reliability)和可维护性(Serviceability)

  • 可靠性使用平均无故障时间(Mean Time Between Failure,MTBF)来度量;
  • 可维护性使用平均可修复时间(Mean Time To Repair,MTTR)来度量。
  • 可用性衡量系统可以正常使用的时间与总时间之比,其表征为:A=MTBF/(MTBF+MTTR),即可用性是由可靠性和可维护性计算得出的比例值,譬如 99.9999%可用,即代表平均年故障修复时间为 32 秒。

第一版解释和第二版解释主要差异点表现在以下几个方面:

  • 第一版是 every request,第二版强调了 A non-failing node。
  • 第一版的every request是不严谨的,因为只有非故障节点才能满足可用性要求,如果节点本身就故障了,发给节点的请求不一定能得到一个响应。
  • 第一版的response分为success和failure,第二版用了两个reasonable:reasonable response 和reasonable time,而且特别强调了 no error or timeout。

第一版的success/failure的定义太泛了,几乎任何情况,无论是否符合CAP理论,我们都可以说请求成功和失败,因为超时也算失败,错误也算失败,异常也算失败,结果不正确也算失败;即使是成功的响应,也不一定是正确的。例如,本来应该返回100,但实际上返回了90,这就是成功的响应,但并没有得到正确的结果。相比之下,第二版的解释明确了不能超时,不能出错,结果是合理的,注意没有说“正确”的结果。例如,应该返回100但实际上返回了90,肯定是不正确的结果,但可以是一个合理的结果。

分区容忍性

分区容忍性(Partition Tolerance):代表分布式环境中部分节点因网络原因而彼此失联后,即与其他节点形成“网络分区”时,系统仍能正确地提供服务的能力。

官方的两个解释如下:

版本 英文定义 翻译
第一版 System continues to work despite message loss or partial failure. 尽管出现消息丢失或分区错误,但系统能够继续运行
第二版 The system will continue to function when network partitions occur. 当出现网络分区后,系统能够继续“履行职责”

第一版解释和第二版解释主要差异点表现在以下几个方面。

  • 第一版用的是work,第二版用的是function。work强调“运行”,只要系统不宕机,我们都可以说系统在work:返回错误也是work,拒绝服务也是work:而function强调“发挥作用”“履行职责”,这点和可用性是一脉相承的。也就是说,只有返回reasonable response才是function。相比之下,第二版解释更加明确。

  • 第一版描述分区用的是message loss or partial failure,第二版直接用network partitions。.相比之下,第一版是直接说原因,即message loss造成了分区,但message loss的定义有点狭隘,因为通常我们说的message loss(丢包),只是网络故障中的一种:第二版直接说现象,即发生了分区现象,不管是什么原因,可能是丢包,也可能是连接中断,还可能是拥塞,只要导致了网络分区,就通通算在里面。

CAP理论的应用

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

CAP 理论的定义和解释中,用的都是 system、 node 这类系统级的概念,这就给很多人造成了很大的误导,认为我们在进行架构设计时,整个系统要么选择 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 的数据存储在 Node 1,将用户 id 为 101 ~ 200 的数据存储在 Node 2, Client 根据用户 id 来决定访问哪个 Node。 对于单个用户来说,读写操作都只能在某个 节点上进行;对所有用户来说,有 一部分用户的读写操作在 Node l 上,有一部分用户的读写操 作在 Node2上。
这样的设计有 一个很明显的问题就是某个节点故障时,这个节点上的用户就无法进行读写 操作了,但站在整体上来看,这种设计可以降低节点故障时受影响的用户的数量和范围,毕竟 只影响 20%的用户肯定要比影响所有用户要好 。 这也是为什么挖掘机挖断光缆后,支付宝只有 一部分用户会出现业务异常,而不是所有用户业务异常的原因 。

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

CAP 理论告诉我们分布式系统只能选择 CP 或 AP,但其实这里的前提是系统发生了“分区” 现象。如果系统没有发生分区现象,也就是说 P 不存在的时候(节点间的网络连接一切正常), 我们没有必要放弃 C 或 A,应该 C 和 A 都可以保证,这就要求架构设计的时候既要考虑分区发 生时选择 CP 还是 AP,也要考虑分区没有发生时如何保证 CA。
同样以用户管理系统为例,即使是实现 CA,不同的数据实现方式也可能不一样: 用户账 号数据可以采用“消息队列”的方式来实现 CA,因为消息队列可以比较好地控制实时性,但 实 现起来就复杂 一 些:而用户信息数据可以采用“数据 库 同步”的方式来实现 CA,因为数据 库的方式虽然在某些场景下可能延迟较高,但使用起来简单 。

ACID 中讨论的一致性称为“强一致性”(Strong Consistency),有时也称为“线性一致性”(Linearizability,通常是在讨论共识算法的场景中),而把牺牲了 C 的 AP 系统又要尽可能获得正确的结果的行为称为追求“弱一致性”。

在弱一致性里,人们又总结出了一种稍微强一点的特例,被称为“最终一致性”(Eventual Consistency),它是指:如果数据在一段时间之内没有被另外的操作所更改,那它最终将会达到与强一致性过程相同的结果,有时候面向最终一致性的算法也被称为“乐观复制算法”。

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

CAP理论告诉我们三者只能取两个,需要“牺牲(sacrificed)”另外一个,这里的“牺牲” 是有一定误导作用的,因为“牺牲”让很多人理解为什么都不做。实际上, CAP 理论的“牺牲” 只是说在分区过程中我们无法保证 C 或 A,但并不意味着我们什么都不做。

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

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

而对于用户信息数据,假设我们选择了 AP,则分区发生后,节点 l 和节点 2 都可以修改用
户信息,但两边可能修改不一样。例如,用户在节点 l 中将爱好改为“旅游,美食、跑步飞然 后用户在节点 2 中将爱好改为“美食、游戏”,节点 l 和节点 2 都记录了未同步的爱好数据,当 分区恢复后,系统按照某个规则来合并数据。例如,按照“最后修改优先规则”将用户爱好修 改为“美食、游戏”,按照“字数最多优先规 则”则 将用户爱好修改为“旅游,美食、跑步”, 也可以完全将数据冲突报告出来,由人工来选择具体应该采用哪 一条 。

Base 理论

BASE理论是指,Basically Available(基本可用)、Soft-state( 软状态/柔性事务)、Eventual Consistency(最终一致性)。是基于CAP定理演化而来,是对CAP中一致性和可用性权衡的结果。核心思想:即使无法做到强一致性,但每个业务根据自身的特点,采用适当的方式来使系统达到最终一致性。

  • 1、基本可用 BA:(Basically Available ):

指分布式系统在出现故障的时候,允许损失部分可用性,保证核心可用。但不等价于不可用。比如:搜索引擎0.5秒返回查询结果,但由于故障,2秒响应查询结果;网页访问过大时,部分用户提供降级服务等。简单来说就是基本可用。

  • 2、软状态 S:( Soft State):

软状态是指允许系统存在中间状态,并且该中间状态不会影响系统整体可用性。即允许系统在不同节点间副本同步的时候存在延时。简单来说就是状态可以在一段时间内不同步。

  • 3、最终一致性 E:(Eventually Consistent ):

系统中的所有数据副本经过一定时间后,最终能够达到一致的状态,不需要实时保证系统数据的强一致性。最终一致性是弱一致性的一种特殊情况。BASE理论面向的是大型高可用可扩展的分布式系统,通过牺牲强一致性来获得可用性。ACID是传统数据库常用的概念设计,追求强一致性模型。简单来说就是在一定的时间窗口内, 最终数据达成一致即可。

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

  • (1) CAP 理论是忽略延时的,而实际应用中延时是无法避免的。这一点就意味着完美的 CP 场景是不存在的,即使是几毫秒的数据复制延迟,在这几毫秒 时间间隔内,系统是不符合 CP 要求的 。 因此 CAP 中的 CP 方案,实际上也是实现了最终一致 性,只是“一定时间”是指几毫秒而己 。

  • (2) AP 方案中牺牲一致性只是指分区期间,而不是永远放弃一致性。这一点其实就是 BASE 理论延伸的地方,分区期间牺牲一致性,但分区故障恢复后,系统应该达到最终一致性 。



支付宝打赏 微信打赏

赞赏一下