NoSQL的三大基石(CAP、BASE和最终一致性)
CAP,BASE和最终一致性是NoSQL数据库存在的三大基石。
CAP理论
CAP原则是NOSQL数据库的基石。
brewer2000年提出的分布式系统的CAP理论
- 一致性(C Consistency): 在分布式系统中的所有数据备份,在同一时刻是否有同样的值。(等同于所有节点访问同一份最新的数据副本。)
- 可用性(A Availability): 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性。)
- 分区容忍性(P Partition tolerance): 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在一定时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
Lynch2002年提出的分布式系统的CAP理论
- 一致性(C Consistency): 一致性被称为原子对象,任何的读写都应该看起来是“原子”的,或者串行的。写后面的读一定能读到前面写的内容。所有的读写请求都好像被全局排序。
- 可用性(A Availability): 对任何非失败节点都应该在有限时间内给出请求的回应。(请求的可终止性)
- 分区容忍性(P Partition tolerance): 允许节点之间丢失任意多的消息,当网络分区发生时,节点之间的消息可能会完全丢失。
CAP的简单理解
- 一致性(C Consistency): 满足C,所有的机器上的数据都是一样,这样的情况下会有什么需求呢?每当一个新数据新增到其中一个服务器上,这个数据要同步到其它服务器,这样的情况下才可以保证C
- 可用性(A Availability): 满足A,这样的情况下会有什么需求呢?用户随时都在访问,都能在可控的时间内返回正确的数据
- 分区容忍性,可靠性(P Partition tolerance): 满足P,非常可靠,怎么能可靠呢?那必须是机器越多越可靠,为啥?我有1亿台服务器,挂了几万台,完全没影响嘛。
CA without P
而不满足 P 意味着当网络分区没有发生时,系统既能满足 A,也能满足C,而当存在网络分区时,将不再保证 A,C。
CA系统更多的是允许分区后各子系统依然保持CA. 典型放弃分区容忍性的例子有关系型数据库、LDAP等。
满足C需要所有的服务器的数据要一样,也就是说要实现数据的同步,那么同步要不要时间?肯定是要的,并且机器越多,同步的时间肯定越慢,这里问题就来了,我们同时也满足了A, 也就是说,我要同步时间短才行。这样的话,机器就不能太多了,也就是说P是满足不了的。
CP without A
如果不要求A,相当于每个请求都要在Server之间强一致,而P会导致同步时间无限延长,如此CP也是可以保证的。很多数据库分布式事务、分布式锁都是与这种模式。
满足P需要很多服务器,假设有1000台服务器,同时满足了C,也就是说要保证每台机器的数据都一样,那么同步的时间可就很大,在这种情况下,我们肯定是不能保证用户随时访问每台服务器获取到的数据都是最新的,想要获取最新的,可以,你就等吧,等全部同步完了,你就可以获取到了,但是我们的A要求短时间就可以拿到想要的数据啊,这不就是矛盾了,所以说这里A是满足不了了
AP without C
要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会是去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致。 现在好多NoSql,DNS、Web缓存属于这一类。
保证了A和P会导致在同一时间点,各个机器上的数据不一致。
CAP的两个分布式场景
分布式事务
分布式事务一般采用两阶段提交策略来实现,这是一个非常耗时的复杂过程,会严重影响系统效率,在实践中我们尽量避免使用它。在实践过程中,如果我们为了扩展数据容量将数据分布式存储,而事务的要求又完全不能降低。那么,系统的可用性一定会大大降低,在现实中我们一般都采用对这些数据不分散存储的策略。最常使用的关系型数据库,因为这个原因,扩展性(分区可容忍性P)受到了限制,这是完全符合CAP理论的。但同时我们应该意识到,这对NoSQL数据库也是一样的。如果NoSQL数据库也要求严格的分布式事务功能,情况并不会比关系型数据库好多少。只是在NoSQL的设计中,我们往往会弱化甚至去除事务的功能,该问题才表现得不那么明显而已。因此,在扩展性问题上,如果要说关系型数据库是为了保证C、A而牺牲P,在尽量避免分布式事务这一点上来看,应该是正确的。也就是说:关系型数据库应该具有强大的事务功能,如果分区扩展,可用性就会降低;而NoSQL数据库干脆弱化甚至去除了事务功能,因此,分区的可扩展性就大大增加了。
关系型数据库支持分布式事务,而分布式事务是一个非常耗时的操作,影响效率。所以这就是一个矛盾,如果想支持分布式事务,在分区过多的情况下,A (Availability)就不能保证了,所以关系型数据库为了保证A而舍弃了P(可靠性、可扩展性)。
- NoSQL数据库弱化了事务功能,同时为了高可用和可靠性,牺牲了C一致性。
分布式表关联
- 对一个数据库来讲,采用了分区扩展策略来扩充容量,数据分散存储了,很显然多表关联的性能就会下降,因为我们必须在网络上进行大量的数据迁移操作,这与CAP理论中数据副本之间的同步操作本质上也是相同的。因此,如果要保证系统的高可用性,需要同时实现强大的多表关系操作的关系型数据库在分区可扩展性上就遇到了极大的限制,而NoSQL数据库则干脆在设计上弱化甚至去除了多表关联操作。那么,从这一点上来理解“NoSQL数据库是为了保证A与P,而牺牲C”的说法,也是可以讲得通的。
结论
- 如果将CAP理论中的C认为是指多个数据副本之间读写一致性的问题,那么它对关系型数据库与NoSQL数据库来讲是完全一样的,它只是运行在分布式环境中的数据管理设施在设计读写一致性问题时需要遵循的一个原则而已,却并不是NoSQL数据库具有优秀的水平可扩展性的真正原因。
- 如果将CAP理论中的一致性C理解为读写一致性、事务与关联操作的综合,则可以认为关系型数据库选择了C与A,而NoSQL数据库则全都是选择了A与P。
BASE理论
Basically Available--基本可用
Soft-state --软状态/柔性 事务
- "Soft state" 可以理解为"无连接"的, 而 "Hard state" 是"面向连接"的
Eventual Consistency --最终一致性
- 最终一致性, 也是是 ACID 的最终目的。
BASE模型反ACID模型,完全不同ACID模型,牺牲高一致性,获得可用性或可靠性: Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库) Soft state软状态 状态可以有一段时间不同步,异步。 Eventually consistent最终一致,最终数据是一致的就可以了,而不是时时一致。
BASE思想主要强调基本的可用性,如果你需要高可用性,也就是纯粹的高性能,那么就要以一致性或容错性为牺牲,BASE思想的方案在性能上还是有潜力可挖的。
最终一致性
一言以蔽之:过程松,结果紧,最终结果必须保持一致性
强一致性
- 强一致性(即时一致性) 假如A先写入了一个值到存储系统,存储系统保证后续A,B,C的读取操作都将返回最新值
弱一致性
- 假如A先写入了一个值到存储系统,存储系统不能保证后续A,B,C的读取操作能读取到最新值。此种情况下有一个“不一致性窗口”的概念,它特指从A写入值,到后续操作A,B,C读取到最新值这一段时间。
最终一致性
- 最终一致性是弱一致性的一种特例。假如A首先write了一个值到存储系统,存储系统保证如果在A,B,C后续读取之前没有其它写操作更新同样的值的话,最终所有的读取操作都会读取到最A写入的最新值。此种情况下,如果没有失败发生的话,“不一致性窗口”的大小依赖于以下的几个因素:交互延迟,系统的负载,以及复制技术中replica的个数(这个可以理解为master/salve模式中,salve的个数),最终一致性方面最出名的系统可以说是DNS系统,当更新一个域名的IP以后,根据配置策略以及缓存控制策略的不同,最终所有的客户都会看到最新的值。
Causal consistency(因果一致性)
- 如果Process A通知Process B它已经更新了数据,那么Process B的后续读取操作则读取A写入的最新值,而与A没有因果关系的C则可以最终一致性。
Read-your-writes consistency (读己所写一致性)
- 如果Process A写入了最新的值,那么Process A的后续操作都会读取到最新值。但是其它用户可能要过一会才可以看到。
Session consistency (会话一致性)
- 此种一致性要求客户端和存储系统交互的整个会话阶段保证Read-your-writes consistency. Hibernate的session提供的一致性保证就属于此种一致性。
Monotonic read consistency (单调读一致性)
- 此种一致性要求如果Process A已经读取了对象的某个值,那么后续操作将不会读取到更早的值。
Monotonic write consistency (单调写一致性) 此种一致性保证系统会序列化执行一个Process中的所有写操作。