之前我们讨论了传统的数据库事务的 ACID 特性: 解读事务的ACID! 其实传统数据库和 NoSQL 中对于可用性、一致性的理解不一样。 因为有时候会听到一些新型数据库宣称满足强一致、高可用、且多地多中心容忍网络分区,但是 CAP 不是说不能三者同时满足吗?这些矛盾来源于对 CAP 理解有偏差。今天来讨论一下 NoSQL 的 CAP 理论。
本文预计阅读时间 7 分钟。
NoSQL数据库
一种新技术的出现是需求推动的,那么对数据库的什么需求推动了 NoSQL 的出现呢?看看传统数据库在使用时的一些问题:
(1)大数据量情况下吞吐率达不到要求,有单点瓶颈。
(2)事务的ACID特性要求太高,很多应用场景不需要这个约束。
(3)具有单点故障,机器宕机后就没法用了,虽然可以做主从,但是还需要人为干预,有一段时间不可用。
(4)单节点存不下全部数据。
(5)数据容易丢失,不做主备的话数据只有一份,磁盘坏掉数据就丢了。
因此,传统数据库一般应用于银行系统、医疗系统这些对操作的要求比较高或者数据量不大的场景。而一些需要高可用性的应用,如Facebook、淘宝、亚马逊等,传统数据库就无法满足要求。
于是,人们希望抛弃传统数据库的思想,构建分布式 NoSQL 数据库,这种数据库有下面几个目标:
(1)每个节点都可以提供读写服务,提高系统吞吐率,可动态增删节点,集群的吞吐率随着节点的增加而线性增长。
(2)去掉了事务,只提供比较简单的读写接口。
(3)避免单点故障,由多个节点组成的集群,一个节点坏了其他节点还能提供服务。
(4)所有节点的磁盘都可以用来存储数据,提供分布式存储能力。
(5)为保证数据不丢失,采用副本机制,一个数据存多份,分别放在不同节点。
(6)为了控制数据的存储位置,还提出了数据分区的概念。
CAP理论
1998年 UC Berkeley 的 Eric Brewer 提出了 CAP 理论,1999年一篇论文进行了总结
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.67.6951&rep=rep1&type=pdf
在构建 NoSQL 数据库时,往往需要在很多方面做平衡。Brewer 在2000年左右提出了 CAP 理论, Consistency、Availability、Partition Tolerance 的首字母缩写。
CAP理论:一个分布式系统不可能同时满足一致性、可用性和分区容错性,最多只能同时满足其中的两个。
这个分布式系统一般是指在异步网络中的,异步网络中没有全局时钟,节点只能根据接收到的消息和本地计算做决策。
有的对 CAP 的误解也来源于对这三个性质的具体含义不清,下面我们先看看这三个性质分别指什么。
一致性
CAP 的一致性与传统关系数据库中 ACID 的 C 不一样。ACID 中的 C 关心的是数据库中的约束,有对单个数据值的约束,也有对多个数据之间值的约束。而CAP 的一致性关心的是一个数据项不同副本的值是否相同。
在 NoSQL 数据库中,由于数据有多个副本,一个写操作需要更新所有副本,由于存在节点间通讯的延迟,可能有的节点的副本被更新了,有的还是旧值,这时读取不同的副本返回的值就会不一致。因此,CAP 中的一致性指的是副本一致性,或者相互一致性(mutual Consistency),他们和一个瞬时状态有关,这个状态叫相互一致:
相互一致:如果系统中每个数据项的所有副本的值都相同,那么系统处于相互一致的状态。在某一时刻,这个状态只有满足或不满足两种情况。
我们可以认为 NoSQL 数据库仅提供简单的对单个数据项的读写操作,如 write(a),read(b),write(b)等,在这种情况下,一致性的表现就和不同节点间读写操作的顺序有关了。因此,很多一致性级别在规定读写操作的顺序和结果。
CAP中的一致性指的是强一致性:当更新事务提交时,所有副本处于相互一致的状态。
从操作的角度看:所有操作必须存在一个全局唯一顺序,使每个操作看起来好像是在一个瞬间完成的。在这种情况下,在一个写操作之后的读操作可以读到这个写的值。
所有节点都可以读到已经更新的结果,看起来就像是一个单机数据库,而且操作是串行的,和ACID隔离性中的可串行化隔离级别一样。
可用性
CAP 中的可用性指的是系统每个节点都能处理请求(接收请求并返回结果)。
而一般传统数据库的可用性是指系统做为一个整体能否对外提供服务,只要有一个节点或多数节点能提供响应就可以称为可用。
分区容忍性
分区就是网络分区,即一个集群被分割成了多个分区,每个分区内部的节点可以通信,而无法跨分区交流,而且这个分区要假设是可能永久存在的。网路分区是分布式系统中逃不掉的。
而分区容忍性则是说在出现网络分区时,系统能否正常对外提供服务。
举例
这张图是CAP里比较经典的图了。由于没有NoSQL同时满足三个,因此只能二选一。
传统数据库由于只有一个节点,没有网络分区问题,正常情况下可以实现强一致性和可用性。而传统数据库的主备技术则是牺牲了可用性来保证一致性。
由于 NoSQL 数据库中网络分区是不可避免的,当出现网络分区时,如下图左图,当接收到一个写操作 A=2(这个写请求只会被发送到一个节点上),我们假设每个节点执行操作需要得到另外两个节点的认可才能执行并返回结果。这时只能在一致性和可用性里二选一。
如果保证一致性,那么任何接收到请求的节点都无法收到全部节点的认同,所以这个操作会被悬挂,最终返回超时或执行错误。
如果保证可用性,可能有一个网络分区接收到这个写请求,并在当前分区内同步写请求,这是就会与另一个分区数据不一致。这个分区是随机的,可能是上图所示的 N3,也可能是 N1 和 N2。
总结
有人诟病 CAP 理论,认为 CAP 中的 P 是废话,或者 CAP 太简单了,没有量化,对实际系统的构建没有具体的指导意义。比如我要牺牲一致性,牺牲到什么程度?一致性也有很多种级别,强一致性、因果一致性、最终一致性等。这个在 CAP 中是没有说的。这确实是 CAP 理论的局限,但是 CAP 理论让人们在构建系统时,聚焦于这三个性质,并从这三个方面来进行权衡。