架构设计那些事儿--CAP和BASE理论


分布式系统(distributed system)正变得越来越重要,大型网站几乎都是分布式的。分布式系统的最大难点,就是各个节点的状态如何同步。CAP 定理是这方面的基本定理,也是理解分布式系统的起点。

本文介绍该定理。它其实很好懂,而且是显而易见的。下面的内容主要参考了 Michael Whittaker 的文章

一、分布式系统的三个指标

img
1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。

  • Consistency
  • Availability
  • Partition tolerance
    它们的第一个字母分别是 C、A、P。

Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理

二、Partition tolerance

先看 Partition tolerance,中文叫做”分区容错”。

大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。
img
上图中,G1 和 G2 是两台跨区的服务器。G1 向 G2 发送一条消息,G2 可能无法收到。系统设计的时候,必须考虑到这种情况。

一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。

三、Consistency

Consistency 中文叫做”一致性”。意思是,写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 G1 发起一个写操作,将其改为 v1。
img
接下来,用户的读操作就会得到 v1。这就叫一致性。
img
问题是,用户有可能向 G2 发起读操作,由于 G2 的值没有发生变化,因此返回的是 v0。G1 和 G2 读操作的结果不一致,这就不满足一致性了。
img
为了让 G2 也能变为 v1,就要在 G1 写操作的时候,让 G1 向 G2 发送一条消息,要求 G2 也改成 v1。
img
这样的话,用户向 G2 发起读操作,也能得到 v1。
img

四、Availability

Availability 中文叫做”可用性”,意思是只要收到用户的请求,服务器就必须给出回应。

用户可以选择向 G1 或 G2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。

五、Consistency 和 Availability 的矛盾

一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。

如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,G2 不能读写,没有可用性不。

如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。

综上所述,G2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

CAP权衡

通过CAP理论及前面的证明,我们知道无法同时满足一致性、可用性和分区容错性这三个特性,那要舍弃哪个呢?

我们分三种情况来阐述一下。

CA without P

这种情况在分布式系统中几乎是不存在的。首先在分布式环境下,网络分区是一个自然的事实。因为分区是必然的,所以如果舍弃P,意味着要舍弃分布式系统。那也就没有必要再讨论CAP理论了。这也是为什么在前面的CAP证明中,我们以系统满足P为前提论述了无法同时满足C和A。

比如我们熟知的关系型数据库,如My Sql和Oracle就是保证了可用性和数据一致性,但是他并不是个分布式系统。一旦关系型数据库要考虑主备同步、集群部署等就必须要把P也考虑进来。

其实,在CAP理论中。C,A,P三者并不是平等的,CAP之父在《Spanner,真时,CAP理论》一文中写到:

如果说Spanner真有什么特别之处,那就是谷歌的广域网。Google通过建立私有网络以及强大的网络工程能力来保证P,在多年运营改进的基础上,在生产环境中可以最大程度的减少分区发生,从而实现高可用性。

从Google的经验中可以得到的结论是,无法通过降低CA来提升P。要想提升系统的分区容错性,需要通过提升基础设施的稳定性来保障。

所以,对于一个分布式系统来说。P是一个基本要求,CAP三者中,只能在CA两者之间做权衡,并且要想尽办法提升P。

CP without A

如果一个分布式系统不要求强的可用性,即容许系统停机或者长时间无响应的话,就可以在CAP三者中保障CP而舍弃A。

一个保证了CP而一个舍弃了A的分布式系统,一旦发生网络故障或者消息丢失等情况,就要牺牲用户的体验,等待所有数据全部一致了之后再让用户访问系统。

设计成CP的系统其实也不少,其中最典型的就是很多分布式数据库,他们都是设计成CP的。在发生极端情况时,优先保证数据的强一致性,代价就是舍弃系统的可用性。如Redis、HBase等,还有分布式系统中常用的Zookeeper也是在CAP三者之中选择优先保证CP的。

无论是像Redis、HBase这种分布式存储系统,还是像Zookeeper这种分布式协调组件。数据的一致性是他们最最基本的要求。一个连数据一致性都保证不了的分布式存储要他有何用?

在我的Zookeeper介绍(二)——Zookeeper概述一文中其实介绍过zk关于CAP的思考,这里再简单回顾一下:

ZooKeeper是个CP(一致性+分区容错性)的,即任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性。但是它不能保证每次服务请求的可用性,也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果。ZooKeeper是分布式协调服务,它的职责是保证数据在其管辖下的所有服务之间保持同步、一致。所以就不难理解为什么ZooKeeper被设计成CP而不是AP特性的了。

AP wihtout C

要高可用并允许分区,则需放弃一致性。一旦网络问题发生,节点之间可能会失去联系。为了保证高可用,需要在用户访问时可以马上得到返回,则每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。

这种舍弃强一致性而保证系统的分区容错性和可用性的场景和案例非常多。前面我们介绍可用性的时候说到过,很多系统在可用性方面会做很多事情来保证系统的全年可用性可以达到N个9,所以,对于很多业务系统来说,比如淘宝的购物,12306的买票。都是在可用性和一致性之间舍弃了一致性而选择可用性。

你在12306买票的时候肯定遇到过这种场景,当你购买的时候提示你是有票的(但是可能实际已经没票了),你也正常的去输入验证码,下单了。但是过了一会系统提示你下单失败,余票不足。这其实就是先在可用性方面保证系统可以正常的服务,然后在数据的一致性方面做了些牺牲,会影响一些用户体验,但是也不至于造成用户流程的严重阻塞。

但是,我们说很多网站牺牲了一致性,选择了可用性,这其实也不准确的。就比如上面的买票的例子,其实舍弃的只是强一致性。退而求其次保证了最终一致性。也就是说,虽然下单的瞬间,关于车票的库存可能存在数据不一致的情况,但是过了一段时间,还是要保证最终一致性的。

对于多数大型互联网应用的场景,主机众多、部署分散,而且现在的集群规模越来越大,所以节点故障、网络故障是常态,而且要保证服务可用性达到N个9,即保证P和A,舍弃C(退而求其次保证最终一致性)。虽然某些地方会影响客户体验,但没达到造成用户流程的严重程度。

适合的才是最好的

上面介绍了如何CAP中权衡及取舍以及典型的案例。孰优孰略,没有定论,只能根据场景定夺,适合的才是最好的。

对于涉及到钱财这样不能有一丝让步的场景,C必须保证。网络发生故障宁可停止服务,这是保证CP,舍弃A。比如前几年支付宝光缆被挖断的事件,在网络出现故障的时候,支付宝就在可用性和数据一致性之间选择了数据一致性,用户感受到的是支付宝系统长时间宕机,但是其实背后是无数的工程师在恢复数据,保证数数据的一致性。

对于其他场景,比较普遍的做法是选择可用性和分区容错性,舍弃强一致性,退而求其次使用最终一致性来保证数据的安全。这其实是分布式领域的另外一个理论——BASE理论。

Base理论

Base理论是Basically Available(基本可用)、Soft state(软状态)、Eventually consistent(最终一致性)的缩写;它基于CAP定理逐步演化来的,它是CAP中一致性和可用性权衡的结果,其核心思想是即使系统无法达到强一致性,可以根据应用自身的业务特点,采用适当的方式来使系统达到最终一致性。

基本可用(Basically Available)

基本可用是指当分布式系统发生故障的时候,允许损失部分可用性。常见的有以下几种情况:

  • 响应时间上的损失:正常情况下,一个在线搜索引擎需要再0.5秒之内返回给用户响应的查询结果,但由于出现故障,查询结果的响应时间增加到了1~2秒。
  • 功能上的损失:通常的做法是降级服务,如对于展示一些有序元素的页面,但部分组件出现故障时,这个时候可不展示有序元素,降级为无序元素列表。

软状态

软状态是指允许系统中的数据存在中间状态,并认为该中间状态的存在不影响系统的整体可用性,即允许系统不同节点的数据副本之间进行数据同步的过程中存在延时。

最终一致性

最终一致性强调的是系统所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

总结

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

CAP理论严格来讲不是三选二,而是CP、AP二选一,因为通常P(分区容错性)是必须得到保证的。

BASE理论面向的是大型高可用、可扩展的分布式系统。与传统ACID特性相反,不是强一致性模型,BASE提出通过牺牲强一致性来获得可用性,并允许数据一段时间内的不一致,但是最终需要达到一致状态。