1.1 再谈CAP

2021/06/19 分布式 共 5833 字,约 17 分钟

1、CAP theorem

在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer’s theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:

  • 一致性(Consistency) (等同于所有节点访问同一份最新的数据副本)
  • 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据)
  • 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。)

根据CAP定理,分布式系统只能满足三项中的两项,当没有网络分区的场景,我们可以同时提供ConsistencyAvailability,当发生网络分区,我们需要在ConsistencyAvailability中取舍;

1.1、AP/CP伪二分法

网络分区是一个错误,而非一个选项:不管你喜不喜欢都会发生,CAP三选二,这个说法有误导性。实际上在分布式系统中,我们只能在A&C中权衡取舍。因此,我们经常可以听到Zookeeper是个CP系统,Redis是个AP系统。我们说一个系统是AP或者是CP,想要表达的是这个系统在设计的时候,CAP的取舍中,偏向AP或者CP,并不是说一个AP系统就不保证一致性,或者一个CP系统就完全不保证可用性。常见的AP、CP系统划分如下:

  • AP: Redis、Eureka

  • CP:Zookeeper、HBase

然而,将系统简单的划分为AP/CP并不严谨:

  • 实际上很多系统不是线性一致性,也并比提供CAP中描述的可用性;
  • 同一个软件内,可能有多个属性的选择,在某些配置下是偏向CP、某些配置下是偏向AP。
  • 有些系统可能即不满足CAP中的A,也不满足CAP中的C;
  • CAP中C与A的取舍可以再同一个系统内非常小的粒度反复发生;
  • Eric Brewer承认CAP是一个容易误导人而且过于简化的模型。

这种粗暴的二分法也并非一无是处,它确实有助于我们简化理解系统设计的权衡取舍。这也有可能是它广泛流传的原因。

1.2、如何理解实现了Zab共识算法的Zookeeper没有同时满足CAP?

如我们所知,Zookeeper实现了Zab协议,类Paxos的共识协议,通常我们认为Zookeeper是选择了一致性,放弃了可用性,也就是CP系统。

那么问题来了,在Network Partition发生时,Zookeeper能根据Zab协议选举新的Leader提供服务,为什么说Zookeeper是一个CP系统呢?

直觉上,我们认为Zab、Paxos、Raft这类共识算法提供了高可用服务,同时满足Linearizability Consistency,这似乎与CAP定理相违背。要解答这个问题,我们需要重新回到CAP定理对可用性的定义:CAP中的A是指100%的Availability,要求任意节点都能立刻(real-time)得到响应。

这个A的定义其实比较迷惑,实际应用中的可用性和CAP可用性并不相同。你应用的可用性多数是通过SLA来衡量的(比如99.9%的正确的请求一定要在一秒钟之内返回成功),但是一个系统无论是否满足CAP可用性其实都可以满足这样的SLA。

ZooKeeper的可用性:要求达到大多数quorum,来达到共识,才能处理一个写操作。如果你有网络分区,一边有大多数节点,一边有少部分节点。那么拥有大多数节点的分区还可以继续工作,但是少部分节点的分区就算节点们都正常工作着,还是不能处理写操作。所以ZooKeeper得写操作在网络分区的情况下,不满足CAP的可用性(即使拥有大多数节点的分区还是可以处理写操作的)

2、再谈CAP

2.1、重新审视CAP的定义

到这里,我们已经了解CAP中P:Network Partition是一个错误,而不是一个选项,而CAP中的A:100% Availability不是一个非0即1的离散变量。CAP中CAP好像并没有我们想象中的那么简单,我们有必要审视CAP的定义:

  • 一致性(Consistency):线性一致性Linearizability Consistency
    1. Linearizability Consistency系统的表现就像按照某个实际的时间顺序来处理所有 client 的读写请求
    2. 线性一致性Linearizability Consistency是很强的一致性,很多系统在Partition未发生的时候,也不提供线性一致性;
  • 可用性(Availability): Read&Write Availability (100%)
    1. CAP中的Availability是一个很狭窄的定义,不是一个非0即1的离散变量;
    2. 要求任意节点都能立刻(real-time)得到响应;
    3. 实际应用中的可用性和CAP可用性并不相同。你应用的可用性多数是通过SLA来衡量的(比如99.9%的正确的请求一定要在一秒钟之内返回成功),一个系统无论是否满足CAP可用性其实都可以满足这样的SLA。
  • 分区容错性(Partition tolerance):Network Partition Tolerance
    • Network Partition 并非一个选项,你喜不喜欢都会发生;(CAP的三选二,实际是二选一,Partition没得选)

2.2、CAP之惑

Eric Brewer承认CAP是一个容易误导人而且过于简化的模型,围绕CAP有很多误解和困惑。

  • Consistency、Partition是一个系统模型,Availability是一个观测指标;
    • Consistency仅考虑线性一致性,线性一致性是一个很强的一致性,实际项目中我们并不一定需要这么强的一致性;
    • Partition非一个选项,喜不喜欢都会发生,CAP中的三选二,实际上是二选一,另外Partition发生的概率很低,我们只需要在Partition发生的时候C/A中二选一即可;
    • Availability要求任意一个节点都有一个real-time的响应,跟SLA定义的高可用不同。在实际的多副本系统中,我们只需要有其中一个节点能提供real-time的响应即可。
  • CAP仅限定一个狭隘的范围,仅考虑了线性一致性和网络分区,没有考虑时延Latency

CAP定理强调CAP不能同时满足,只能同时满足其中的两项,考虑到现在的网络Partition出现的概率很低,在Partition没有出现的时候实际上C、A可以同时满足;当Partition出现的时候我们才需要从Linearizability Consistency、100%的Availability中二选一。

尽管CAP在历史上很有影响力,但是对设计系统而言并没有实际的价值。–摘自Distributed Data Intensisive Applications

3、CAP→PACELC

有意思的是CAP中的Availability指的是100%的Availability,要求任意节点都有一个real-time的响应,real-time的响应其实和Latency是一回事。CAP定理中没有提到系统时延(Latency),而时延却是可用性Availability的重要因素,因此延伸出PACELC理论。

PACELC定理是CAP的扩展,PACELC在wiki上的定义:

It states that in case of network partitioning (P) in a distributed computer system, one has to choose between availability (A) and consistency (C) (as per the CAP theorem), but else (E), even when the system is running normally in the absence of partitions, one has to choose between latency (L) and consistency (C).

如果有分区 partition (P),系统就必须在 availability 和 consistency (A and C)之间取得平衡; 否则 else (E) 当系统运行在无分区情况下,系统需要在 latency (L) 和 consistency (C)之间取得平衡。

要保证高可用High Availability,有效的提升可用性的方法就是通过复制技术实现多副本,就需要在Consistency和Latency之间做trade off。

用PACELC来理解Mysql的主从复制就比较容易理解,如果需要强一致性,我们就需要选择同步复制,Latency就会增加。如果选择弱一致性,可以配置异步复制,Latency就会降低;

4、思考

我们经常能听到这样的观点,思考一下它背后的真正逻辑是什么?

4.1、为什么说Redis无法实现严格的分布式锁?

Redis无法实现真正意义上严格的分布式锁,同样我们也无法基于Redis实现分布式场景下严格的幂等保证。他背后的真正逻辑是什么呢?

Redis在CAP的取舍中,更偏向AP,也就是说在Network Partition发生时,Redis更偏向保证可用性,牺牲了线性一致性。当Network Partition发生时,触发Redis Leader Election,当候选的Leader并没有旧Leader的最新数据,Redis更偏向保证系统可用,这个时候可能会产生数据不一致。而分布式锁、分布式场景下的幂等本质是一个共识(Consensus)问题,分布式系统下确定一个不可变的值。所以,从理论上讲Redis是不能实现严格意义上的分布式锁。同理也没办法基础Redis实现分布式场景下真正的幂等保证;

当然,我们如果需要严格的分布式锁,我们可以选择Zookeeper的来实现,但考虑到性能,以及维护成本,稳定性等一系列因素,实际上Redis分布式锁在实际工程中应用的远远要比Zookeeper的锁要广泛。

Redis实现的分布式锁从理论上讲,在Network Partition发生的时候,才有可能出现锁不住的情况。但是考虑到Network Partition不经常发生,另外我们在实际工程实现中,我们常常会在数据持久层基于数据库唯一索引实现一层作为redis分布式锁的兜底,Redis分布式锁仅仅是挡住并发流量,防止高并发引起InnoDB死锁检测,造成CPU占用过高的问题。

4.2、Eureka比Zookeeper从理论上更合适做服务发现?

Zookeeper在CAP的取舍中,更偏向CP,也就是在Network Partition发生,Zookeeper首先考虑的是保证线性一致性。这带来的问题是Zookeeper的可用性降低。然而在服务发现这个业务场景中,可用性要求极高。一旦可出现可用性问题,将引起灾难性的大面积故障。这也是我们常常说Eureka比Zookeeper从理论上更适合做服务发现的本质原因。

但是,我们仍然可以看到各种使用Zookeeper来做服务发现的案例,比如dubbo就支持Zookeeper用于服务发现,这并不意味着引入Dubbo的架构师不了解Zookeeper用来做服务发现的可用性问题。恰恰相反,他们在服务发现的Client端,也就是ZkClient侧,实现一层本地缓存,即是Zookeeper出现了短暂的不可用,仍然可以通过本地缓存中获取服务节点信息。这也是典型牺牲一致性,换取可用性的Case。

服务发现还要负责节点的健康检测Health Checking,具体的实现通常是基于timeout的机制实现。这面临几个挑战:

  1. 怎么判定是网络Latency问题还是Node crash?
  2. timeout的时间怎么确定,几个timeout判断是Node crash?timeout时间太长,服务下线不及时,时间太短容易造成误判。

基于以上两点考虑,Enreka比Zookeeper要实现的更加完善,这里不展开讲。

5、总结

  1. CAP定理中C指的是Linearizability Consistency,是很强的一致性。实际业务场景中,并不经常需要提供这样的强一致性。
  2. CAP中的A指的是100% Availability,是一个非0即1的离散变量,要求任意一个节点都有一个real-time的响应,跟SLA定义的高可用不同。在实际的多副本系统中,我们只需要有其中一个节点能提供real-time的响应即可。
  3. CAP中的P指的是Network Partition,是一个错误而非选项:分布式系统,不管你喜不喜欢Partition都可能会发生。通常我们说CAP三选二其实是有误导性的,分布式系统实际上我们是在A、P中权衡,通常我们说Redis是一个偏向AP的系统,Zookeeper是一个偏向CP的系统。
  4. CAP定理仅限于狭隘的范围,Partition是一个错误,而非选项;Availability指的是100% Availability,非0即1的离散变量,并不能很好的描述高可用性;C则特指线性一致性(Linearizability Consistency),很强的一致性,现在的很多系统,即是在网络未分区的时候,也不提供线性一致性(Linearizability Consistency)。总的来说CAP在历史上有一些影响力,容易让人产生误解,但是对于系统设计的实际价值不大。
  5. CAP定理中没有提到系统时延(Latency),而时延却是影响可用性Availability的重要因素,另外,Partition发生的概率较低,当Partition未发生时,100%的Availability和Linearizability Consistency可以兼得。因此延伸出PACELC理论:如果有分区 partition (P),系统就必须在 availability 和 consistency (A and C)之间取得平衡; 否则 else (E) 当系统运行在无分区情况下,系统需要在 latency (L) 和 consistency (C)之间取得平衡。

6、延伸阅读

  • ACID

  • BASE

  • FTL

  • 关于一致性

  • Linearizability

参考文档

Table of Contents