NoSQL一致性
上面我们讲到了通过将数据冗余存储到不同的节点来保证数据安全和减轻负载,下面我们来看看这样做引发的一个问题:保证数据在多个节点间的一致性是非常困难的。在实际应用中我们会遇到很多困难,同步节点可能会故障,甚至会无法恢复,网络可能会有延迟或者丢包,网络原因导致集群中的机器被分隔成两个不能互通的子域等等。在NoSQL中,通常有两个层次的一致性:第一种是强一致性,既集群中的所有机器状态同步保持一致。第二种是最终一致性,既可以允许短暂的数据不一致,但数据最终会保持一致。我们先来讲一下,在分布式集群中,为什么最终一致性通常是更合理的选择,然后再来讨论两种一致性的具体实现结节。
13.5.1 关于CAP理论 为什么我们会考虑削弱数据的一致性呢?其实这背后有一个关于分布式系统的理论依据。这个理论最早被 Eric Brewer 提出,称为CAP理论,尔后Gilbert 和 Lynch 对CAP进行了理论证明。这一理论首先把分布式系统中的三个特性进行了如下归纳: 一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。 可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。
分区容忍性(P):集群中的某些节点在无法联系后,集群整体是否还能继续进行服务。
而CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。 要保证数据一致性,最简单的方法是令写操作在所有数据节点上都执行成功才能返回成功。而这时如果某个结点出现故障,那么写操作就成功不了了,需要一直等到这个节点恢复。
也就是说,如果要保证强一致性,那么就无法提供7×24的高可用性。 而要保证可用性的话,就意味着节点在响应请求时,不用完全考虑整个集群中的数据是否一致。只需要以自己当前的状态进行请求响应。由于并不保证写操作在所有节点都写成功,这可能会导致各个节点的数据状态不一致。 CAP理论导致了最终一致性和强一致性两种选择。当然,事实上还有其它的选择,比如在Yahoo! 的PNUTS中,采用的就是松散的一致性和弱可用性结合的方法。但是我们讨论的NoSQL系统没有类似的实现,所以我们在后续不会对其进行讨论。
13.5.2 强一致性 强一致性的保证,要求所有数据节点对同一个key值在同一时刻有同样的value值。虽然实际上可能某些节点存储的值是不一样的,但是作为一个整体,当客户端发起对某个key的数据请求时,整个集群对这个key对应的数据会达成一致。下面就举例说明这种一致性是如何实现的。
假设在我们的集群中,一个数据会被备份到N个结点。这N个节点中的某一个可能会扮演协调器的作用。它会保证每一个数据写操作会在成功同步到W个节点后才向客户端返回成功。而当客户端读取数据时,需要至少R个节点返回同样的数据才能返回读操作成功。
而NWR之间必须要满足下面关系:R+W>N 下面举个实在的例子。比如我们设定N=3(数据会备份到A、B、C三个结点)。比如值 employee30:salary 当前的值是20000,我们想将其修改为30000。我们设定W=2,下面我们会对A、B、C三个节点发起写操作(employee30:salary, 30000),当A、B两个节点返回写成功后,协调器就会返回给客户端说写成功了。
至于节点C,我们可以假设它从来没有收到这个写请求,他保存的依然是20000那个值。之后,当一个协调器执行一个对employee30:salary的读操作时,他还是会发三个请求给A、B、C三个节点: 如果设定R=1,那么当C节点先返回了20000这个值时,那我们客户端实际得到了一个错误的值。
如果设定R=2,则当协调器收到20000和30000两个值时,它会发现数据不太正确,并且会在收到第三个节点的30000的值后判断20000这个值是错误的。 所以如果要保证强一致性,在上面的应用场景中,我们需要设定R=2,W=2 如果写操作不能收到W个节点的成功返回,或者写操作不能得到R个一致的结果。那么协调器可能会在某个设定的过期时间之后向客户端返回操作失败,或者是等到系统慢慢调整到一致。这可能就导致系统暂时处于不可用状态。 对于R和W的不同设定,会导致系统在进行不同操作时需要不同数量的机器节点可用。
比如你设定在所有备份节点上都写入才算写成功,既W=N,那么只要有一个备份节点故障,写操作就失败了。一般设定是R+W = N+1,这是保证强一致性的最小设定了。一些强一致性的系统设定W=N,R=1,这样就根本不用考虑各个节点数据可能不一致的情况了。 HBase是借助其底层的HDFS来实现其数据冗余备份的。
HDFS采用的就是强一致性保证。在数据没有完全同步到N个节点前,写操作是不会返回成功的。也就是说它的W=N,而读操作只需要读到一个值即可,也就是说它R=1。为了不至于让写操作太慢,对多个节点的写操作是并发异步进行的。在直到所有的节点都收到了新的数据后,会自动执行一个swap操作将新数据写入。这个操作是原子性和一致性的。保证了数据在所有节点有一致的值。
13.5.3 最终一致性 像Voldemort,Cassandra和Riak这些类Dynamo的系统,通常都允许用户按需要设置N,R,W三个值,即使是设置成W+RHinted Handoff Cassandra、Riak和Voldemort都实现了一种叫Hinted Handoff的技术,用来保证在有节点故障后系统的写操作不受太大影响。它的过程是如果负责某个key值的某个节点宕机了,另一个节点会被选择作为其临时切换点,以临时保存在故障节点上面的写操作。这些写操作被单独保存起来,直到故障节点恢复正常,临时节点会把这些写操作重新迁移给刚刚恢复的节点。
Dynamo 论文中提到一种叫“sloppy quorum”的方法,它会把通过 Hinted Handoff 写成功的临时节点也计算在成功写入数中。但是Cassandra和Voldemort并不会将临时节点也算在写入成功节点数内,如果写入操作并没有成功写在W个正式节点中,它们会返回写入失败。当然,Hinted Handoff 策略在这些系统中也有使用,不过只是用在加速节点恢复上。
Anti-Entropy 如果一个节点故障时间太长,或者是其 Hinted Handoff 临时替代节点也故障了,那么新恢复的节点就需要从其它节点中同步数据了。(译者:实际上就是要找出经过这段时间造成的数据差异,并将差异部分同步过来)。这种情况下Cassandra和Riak都实现了在Dynamo文档中提到的一种方法,叫做anti-entropy。在anti-entropy过程中,节点间通过交换Merkle Tree来找出那些不一致的部分。
Merkle Tree是一个分层的hash校验机制:如果包含某个key值范围的hash值在两个数据集中不相同,那么不同点就在这个key值范围,同理,如果顶层的hash值相同,那么其负责的所有key值范围内的值都认为是相同的。这种方法的好处是,在节点恢复时,不用把所有的值都传一遍来检查哪些值是有变化的。只需要传几个hash值就能找到不一致的数据,重传这个数据即可。
Gossip 当一个分布式系统越来越大,就很难搞清集群中的每个节点的状态了。上面说到的类Dynamo 应用都采用了Dynamo文档中说到的一种古老的方法:Gossip。通过这个方法,节点间能够互相保持联系并能够检测到故障节点。其具体做法是,每隔一段时间(比如一秒),一个节点就会随便找一个曾经有过通信的节点与其交换一下其它节点的健康状态。通过这种方式,节点能够比较快速的了解到集群中哪些节点故障了,从而把这些节点负责的数据分配到其它节点去。
13.6 写在最后的话 目前NoSQL系统来处在它的萌芽期,我们上面讨论到的很多NoSQL系统,他们的架构、设计和接口可能都会改变。本章的目的,不在于让你了解这些NoSQL系统目前是如何工作的,而在于让你理解这些系统之所以这样实现的原因。NoSQL系统把更多的设计工作留给了应用开发工作者来做。理解上面这些组件的架构,不仅能让您写出下一个NoSQL系统,更让您对现有系统应用得更好。
NoSQL一致性的更多相关文章
- NoSql的三大基石:CAP理论&BASE&最终一致性
关系型数据库的局限 NoSql出现在关系型数据库之后,主要是为了解决关系型数据库的短板,我们先来看看随着软件行业的发展,关系型数据库面临了哪些挑战: 1.高并发 一个最典型的就是电商网站,例如双11, ...
- 成为Java顶尖程序员,先过了下面问题!
一.数据结构与算法基础 说一下几种常见的排序算法和分别的复杂度. 用Java写一个冒泡排序算法 描述一下链式存储结构. 如何遍历一棵二叉树? 倒排一个LinkedList. 用Java写一个递归遍历目 ...
- Big Data资料汇总
整理和翻新一下自己看过和笔记过的Big Data相关的论文和Blog Streaming & Spark In-Stream Big Data Processing Discretized S ...
- 想成为顶尖 Java 程序员?请先过了下面这些技术问题。
一.数据结构与算法基础 说一下几种常见的排序算法和分别的复杂度. 用Java写一个冒泡排序算法 描述一下链式存储结构. 如何遍历一棵二叉树? 倒排一个LinkedList. 用Java写一个递归遍历目 ...
- 想成为顶尖 Java 程序员?先过了下面这些问题!
作者:rowkey https://zhuanlan.zhihu.com/p/31552882 一.数据结构与算法基础 说一下几种常见的排序算法和分别的复杂度. 用Java写一个冒泡排序算法 描述一下 ...
- 最全Java架构师130面试题:微服务、高并发、大数据、缓存等中间件
一.数据结构与算法基础 · 说一下几种常见的排序算法和分别的复杂度. · 用Java写一个冒泡排序算法 · 描述一下链式存储结构. · 如何遍历一棵二叉树? · 倒排一个LinkedList. · 用 ...
- NoSQL生态系统——一致性RWN协议,向量时钟,gossip协议监测故障
13.5 一致性 在NoSQL中,通常有两个层次的一致性:第一种是强一致性,既集群中的所有机器状态同步保持一致.第二种是最终一致性,既可以允许短暂的数据不一致,但数据最终会保持一致.我们先来讲一下,在 ...
- NoSQL数据库:数据的一致性
NoSQL数据库:数据的一致性 读取一致性 强一致性 在任何时间访问集群中任一结点,得到的数据结果一致: 用户一致性 对同一用户,访问集群期间得到的数据一致: 解决用户一致性:使用粘性会话,将会话绑定 ...
- NoSQL的三大基石(CAP、BASE和最终一致性)
CAP,BASE和最终一致性是NoSQL数据库存在的三大基石.而五分钟法则是内存数据存储了理论依据.这个是一切的源头. CAP C: Consistency 一致性 A: Availability 可 ...
- 下一代NoSQL:最终一致性的末日
相比关系型数据库,NoSQL解决方案提供了shared-nothing.容错和可扩展的分布式架构等特性,同时也放弃了关系型数据库的强数据一致性和隔离性,美其名曰:"最终一致性". ...
随机推荐
- Charles的https抓包方法及原理/下载ssl/http证书【转】
Charles的https抓包方法及原理/下载ssl/http证书 本文的Charles,适应windows/MAC/IOS/Android,避免抓包HTTPS失败和乱码: charles如果不配 ...
- 聊聊 iframe, CSP, 安全, 跨域
refer : https://www.cnblogs.com/kunmomo/p/12131818.html (跨域) https://segmentfault.com/a/119000000450 ...
- SQL Server – Concurrency 并发控制
前言 以前写过相关的, 但这篇主要讲一下概念. 帮助理解 Entity Framework with MySQL 学习笔记一(乐观并发) Asp.net core 学习笔记 ( ef core tra ...
- Python 潮流周刊#69:是时候停止使用 Python 3.8了(摘要)
本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...
- storybook 7.6
https://storybook.js.org/tutorials/intro-to-storybook/vue/zh-CN/get-started/ 开始吧 注释:degit 从 github 拉 ...
- dfs与贪心算法——洛谷5194
问题描述: 有n个砝码,将砝码从大到小排列,从第三个砝码开始,所有砝码均大于其前两个砝码之和,问怎样的砝码组合才可以组合出不大于c的最大重量,输出该重量 输入: 第一行输入两个个整数N,c,代表有N个 ...
- IntelliJ IDEA插入时间文本
IntelliJ IDEA插入时间文本 需求: 在使用IDEA编辑一些文本时,需要插入指定格式的当前时间文本,首先想到的是找找有没有相关的IDEA插件,看到确实有别的猿做过相关的插件,但当时找到的文章 ...
- 《MySQL 5.7从入门到精通(视频教学版)》代码课件教学视频下载
<MySQL 5.7从入门到精通(视频教学版)>代码课件教学视频下载 https://pan.baidu.com/s/1ZufDV6a_PEnjp-Bdh4IkuQ 提取码:vgnr 无版 ...
- std::stod:“123.456”-> 123.456
std::stod 是 C++ 标准库中一个用于将字符串转换为 double 类型的函数.它属于 <string> 头文件中的函数,通常用于将包含数字的字符串转换为相应的浮点数值. 函数原 ...
- 基于Python后端构建多种不同的系统终端界面研究
在我们一般开发系统的时候,往往会根据实际需要做出各种不同的系统终端界面,如基于BS的,CS.APP.小程序等等,一般都是基于一个统一接入的Web API后端,本篇系统探寻对基于Python后端构建多种 ...