最近在实践分布式和微服务系统,总算是能够把课本上学到的知识学以致用了。于是打算开一个系列来随机聊一聊分布式系统的一些知识。
CAP 理论
CAP 理论中给出了 CAP 布鲁尔定理(Brewer’s theorem),它指对于一个分布式计算系统来说,不可能同时满足以下三点:
- 一致性(Consistency) (所有节点访问同一份最新的数据副本)
- 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据)
- 分区容错性(Partition tolerance)(如果不能在时限内达成数据一致性,则发生分区,必须就当前操作在 C 和 A 之间做出选择。)
证明:反证法。不妨设三个性质均满足(即满足原子性、可用性以及分区容错)。那么任何包含至少两个节点的网络可以分隔为两个非空集合 $G_1, G_2$,我们将网络定义成此种形式。对于一个原子对象 $o$ 的初值 $v_0$。定义 $\alpha_1$ 为一个执行步骤的一部分,并包含了一个对原子对象的写操作,使得原子对象的值变为 $v_1$ 且在 $G_1$ 中 $v_1 \neq v_0$。 假设 $\alpha_1$ 为当前时间段内唯一的客户端请求。那么假设 $G_1$ 和 $G_2$ 之间没有通信。由于满足可用性要求,于是对象 $o$ 在 $G_1$ 中具有值 $v_1$。
同法,不妨设 $\alpha_2$ 是另一个执行步骤的一部分,作用在 $G_2$ 上,于是 $o$ 在 $G_2$ 中具有值 $v_2$。
这时,如果执行一个包含 $\alpha_1$ 和 $\alpha_2$ 的步骤,那么 $G_e$ 仅能观察到 $\alpha_2$ (没有获得关于 $\alpha_1$ 的消息)。从而在 $\alpha_2$ 上的读操作会返回 $v_0$。考虑到读请求仅发生在写操作结束后,这与原子性相违背,证明完毕。
CAP 理论的普遍误解
CAP 理论的完整表述为:Any networked shared-data system can have at most two of the three desired properties。换句话说,CAP 定律的前提是 P,当 P 决定后才有 CA 的抉择。通常人们所理解的三选二其实是一种比较大的误解。分区如果很少发生,那么在系统不存在分区的情况下没什么理由牺牲 C 或 A。其次,C 与 A 之间的取舍可以在同一系统内以非常细小的粒度反复发生,而每一次的决策可能因为具体的操作,乃至因为牵涉到特定的数据或用户而有所不同。最后,这三种性质都可以在程度上衡量,并不是非黑即白的有或无。对于可用性而言,这一指标则是在 0% 到 100% 之间连续变化的,而一致性也分很多级别,甚至连分区也可以细分为不同含义,如系统内的不同部分对于是否存在分区可以有不一样的认知。
ACID 理论与 AC 系统
早期的软件复杂度很低,我们的系统通常满足 ACID 理论。即 CAP 理论中 A+C 可用并一致,ACID 指:
- 原子性(Atomicity):要么事务执行成功、要么事务不执行(失败回滚),不存在中间状态;
- 一致性(Consistency):数据库要么是执行成功的最终结果状态,要么是不执行的状态。数据库不存在事务的中间执行状态;
- 隔离性(Isolation):多个事务之间执行过程中隔离不可见
- 持久性(Durability):事务一旦提交,数据就会落地,即使发生宕机,重启后看到的也是事务提交后的状态
AC 系统在业务相对简单时几乎所向披靡,但一旦业务面临增长,强一致性的原子锁会造成大量的性能消耗。
BASE 理论与 AP 系统
ACID 理论早期服务于 SQL 型数据库,但当引入了分区后事情就变得复杂了起来,根据 CAP 理论,当存在 P 后,需要在 A 与 C 中进行抉择,不能同时满足。AP 系统即为满足 BASE 理论的系统。BASE 则指下面三个方面:
- 基本可用(Basically Available):允许损失部分可用性,即保证核心可用
- 软状态(Soft State):允许系统存在中间状态,不会影响系统整体可用性
- 最终一致性(Eventual Consistency):数据副本经过一定时间后,最终能够达到一致的状态
这里的最终一致性是一个很有意思的话题,围绕一致性的内容有很多可以展开讨论的点。这里的最终一致性其实是弱一致性的一种特殊状况,对于一致性的具体讨论,我们留到以后讨论分布式一致性算法的时候再细说。简单来说,BASE 理论放弃了数据的强一致性,通过最终一致性来保证系统再分区异常时的基本可用性。
评述
总的来说,ACID 和 BASE 代表了两种截然相反的设计哲学,分处一致性-可用性分布图谱的两极。ACID 注重数据的一致性,是数据库的传统设计思路。而 BASE 的目的是抓住当时正逐渐成型的一些针对高可用性的设计思路,并且把不同性质之间的取舍和消长关系摆上台面。对于大规模跨区域分布的系统,包括云在内,则同时运用了这两种思路。
在实际的分布式系统实践中,CAP 理论演变为发生操作的那个短暂的间歇中,系统究竟是选择取消操作从而降低可用性,还是继续操作来冒险损失系统一致性为代价。有时系统依靠多次尝试通信的方法来达到一致性,在 Paxos 算法或者两阶段事务提交,这样的做法仅仅是推迟了决策的时间,但分布式系统终究要做一个决定;而无限期地尝试下去,本身就是选择一致性牺牲可用性的表现。这也是为什么我们说分区其实相当于对通信时限制定了一些要求。如果系统不能在规定的时间内达成数据一致,就认为发生了分区,必须在 C 和 A 之间进行决定。