分布式理论知识

2023/2/11

# CAP 理论

# 官方解释


第一版:对于一个分布式计算系统,不可能同时满足一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三个设计约束

第二版:在一个分布式系统中,当涉及读写操作时,只能保证一致性( Consistence )、可用性( Availability )、分区容错性( Partition Tolerance )三者中的两个,另外一个必须被牺牲


  1. 一致性( Consistency )
    1. 第一版解释:所有节点在同一时刻都能看到相同的数据
    2. 第二版解释:对某个指定的客户端来说,读操作保证能够返回最新的写操作结果
  2. 可用性( Availability )
    1. 第一版解释:每个请求都能得到成功或者失败的响应
    2. 第二版解释:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
  3. 分区容忍性( Partition Tolerance )
    1. 第一版解释:出现消息丢失或者分区错误时系统能够继续运行
    2. 第二版解释:当出现网络分区后,系统能够继续“履行职责”

# 解释

语音解释请点击 (opens new window)

解释了几个问题:

  1. ca、cp、ap 的理解
  2. zookeep 为什么是 cp?
  3. redis 是 ap 还是 cp?
  4. 阿里 polarDB 如果解决网络分区问题?

# 细节

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

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

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


CAP 是忽略网络延迟的

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

不要小看了这几毫秒或者几十毫秒的不一致,对于某些严苛的业务场景,例如和金钱相关的用户余额,或者和抢购相关的商品库存,技术上是无法做到分布式场景下完美的一致性的。而业务上必须要求一致性,因此单个用户的余额、单个商品的库存,理论上要求选择 CP 而实际上 CP 都做不到,只能选择 CA。也就是说,只能单点写入,其他节点做备份,无法做到分布式情况下多点写入

需要注意的是,这并不意味着这类系统无法应用分布式架构,只是说“单个用户余额、单个商品库存”无法做分布式,但系统整体还是可以应用分布式架构的。例如,下面的架构图是常见的将用户分区的分布式架构

image.png

我们可以将用户 id 为 0 ~ 100 的数据存储在 Node 1,将用户 id 为 101 ~ 200 的数据存储在 Node 2,Client 根据用户 id 来决定访问哪个 Node。对于单个用户来说,读写操作都只能在某个节点上进行;对所有用户来说,有一部分用户的读写操作在 Node 1上,有一部分用户的读写操作在 Node 2上

这样的设计有一个很明显的问题就是某个节点故障时,这个节点上的用户就无法进行读写操作了,但站在整体上来看,这种设计可以降低节点故障时受影响的用户的数量和范围,毕竟只影响 20% 的用户肯定要比影响所有用户要好。这也是为什么挖掘机挖断光缆后,支付宝只有一部分用户会出现业务异常,而不是所有用户业务异常的原因


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

但在实际设计过程中,每个系统不可能只处理一种数据,而是包含多种类型的数据,有的数据必须选择 CP,有的数据必须选择 AP 。而如果我们做设计时,从整个系统的角度去选择 CP 还是 AP ,就会发现顾此失彼,无论怎么做都是有问题的

以一个最简单的用户管理系统为例,用户管理系统包含用户账号数据(用户 ID、密码)、用户信息数据(昵称、兴趣、爱好、性别、自我介绍等)。通常情况下,用户账号数据会选择 CP ,而用户信息数据会选择 AP ,如果限定整个系统为 CP ,则不符合用户信息数据的应用场景;如果限定整个系统为AP,则又不符合用户账号数据的应用场景

所以在 CAP 理论落地实践时,我们需要将系统内的数据按照不同的应用场景和要求进行分类,每类数据选择不同的策略( CP 还是 AP ),而不是直接限定整个系统所有数据都是同一策略


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

CAP 理论告诉我们三者只能取两个,需要“牺牲”(sacrifced)另外一个,这里的“牺牲”是有一定误导作用的,因为“牺牲”让很多人理解成什么都不做。实际上,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 中将爱好改为“美食、游戏”,节点 1 和节点 2 都记录了未同步的爱好数据,当分区恢复后,系统按照某个规则来合并数据。例如,按照“最后修改优先规则”将用户爱好修改为“美食、游戏”,按照“字数最多优先规则”则将用户爱好修改为“旅游,美食、跑步”,也可以完全将数据冲突报告出来,由人工来选择具体应该采用哪一条


# BASE

BASE 是指基本可用( Basically Available )、软状态( Soft State )、最终一致性( Eventual Consistency ),核心思想是即使无法做到强一致性( CAP 的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(BASE 是这几个单词的首字母缩写)

  • 基本可用( Basically Available ):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。这里的关键词是“部分”和“核心”,具体选择哪些作为可以损失的业务,哪些是必须保证的业务,是一项有挑战的工作。例如,对于一个用户管理系统来说,“登录”是核心功能,而“注册”可以算作非核心功能。因为未注册的用户本来就还没有使用系统的业务,注册不了最多就是流失一部分用户,而且这部分用户数量较少。如果用户已经注册但无法登录,那就意味用户无法使用系统。例如,充了钱的游戏不能玩了、云存储不能用了……这些会对用户造成较大损失,而且登录用户数量远远大于新注册用户,影响范围更大。
  • 软状态( Soft State ):允许系统存在中间状态,而该中间状态不会影响系统整体可用性
  • 最终一致性( Eventual Consistency ):系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。这里的关键词是“一定时间” 和 “最终”,“一定时间”和数据的特性是强关联的,不同的数据能够容忍的不一致时间是不同的。举一个微博系统的例子,用户账号数据最好能在1分钟内就达到一致状态,因为用户在A节点注册或者登录后,1分钟内不太可能立刻切换到另外一个节点,但10分钟后可能就重新登录到另外一个节点了;而用户发布的最新微博,可以容忍30分钟内达到一致状态,因为对于用户来说,看不到某个明星发布的最新微博,用户是无感知的,会认为明星没有发布微博。“最终”的含义就是不管多长时间,最终还是要达到一致性的状态

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

这一点就意味着完美的 CP 场景是不存在的,即使是几毫秒的数据复制延迟,在这几毫秒时间间隔内,系统是不符合 CP 要求的。因此 CAP 中的 CP 方案,实际上也是实现了最终一致性,只是“一定时间”是指几毫秒而已

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

# CAP 与 BASE 关系

BASE 是对 CAP 中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的结论,是基于CAP定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),更具体地说,是对 CAP 中 AP 方案的一个补充。其基本思路就是:通过业务,牺牲强一致性而获得可用性,并允许数据在一段时间内是不一致的,但是最终达到一致性状态。

# ACID 与 BASE 关系

ACID 是传统数据库常用的设计理念,追求强一致性模型。BASE 支持的是大型分布式系统,提出通过牺牲强一致性获得高可用性。

ACID 和 BASE 代表了两种截然相反的设计哲学,在分布式系统设计的场景中,系统组件对一致性要求是不同的,因此 ACID 和 BASE 又会结合使用。

# 参考

  1. 《从 0 开始学架构》
  2. 分布式理论 - BASE (opens new window)