NoSQL入门(序)

NoSQL简介

实际用例

  • 新浪微博Redis+MySQL,使用200多台物理机
  • 淘宝数据平台Oceanbase,使用的Tair在2010年6月30日对外开源
  • 视觉中国MongoDB
  • 优酷:在线评论使用MongoDB;运营数据分析使用Hadoop/Hbase
  • 飞信空间:使用HandlerSocket
  • 豆瓣社区:使用BeansDB

NoSQL的产生背景

2011年,中国互联网行业持有数据总量达到1.9EB(1EB字节相当于10亿GB)
2011年,全球被创建和复制的数据总量为1.8ZB(1.8万亿GB)
2013年,生成这样规模的信息量只需10分钟
2015年,全球被创建和复制的数据总量将增长到8.2EB以上
2020年,全球电子设备存储的数据将暴增达到40ZB

暴增的海量数据标识着我们进入了大数据时代

大数据

大数据的四个特征

  • 大量化:数据一直都在以每年50%的速度增长,也就是说每两年就增长一倍(大数据摩尔定律)
  • 快速化:从数据的生成到消耗,时间窗口非常小,可用于生成决策的时间非常少
  • 多样化:大数据是由结构化和非结构化数据组成的

非结构化数据类型多样:邮件、视频、微博、位置信息、链接信息、手机呼叫、网页点击、长微博…

  • 价值化:价值密度低,商业价值高

以视频为例,连续不间断监控过程中,可能有用的数据仅仅有一两秒,但是具有很高的商业价值

普通数据和大数据的对比

普通数据大数据
数据规模(基本单位)MBGB以上
数据类型种类单一,且以结构化数据为主种类繁多,且存在结构化、半结构化、非结构化的数据
模式(Schema)和数据的关系先有模式后有数据难以确定模式,多为先有数据后有模式
处理对象数据仅为处理对象以数据为辅助解决其他问题的工具
处理工具一般只需要一种方式(One Size Fits All)需要多种方式(No SIze Fits All)

关系数据库和NoSQL的对比(重点)

关系数据库的优缺点

优点:

  • 通用性和高性能
  • 能保持数据的一致性(事务处理)
  • 能够保证最小冗余
  • 能实现复杂查询如JOIN
  • 拥有成熟的技术

缺点:

  • 不适合在分布式环境中的向外扩展

解释
1、随着用户数的不断增加,中心的数据库服务器的压力会越来越大;如果只为主服务器增加从服务器,那么从服务器只能响应读操作(适用于读操作大于写操作的情形);如果增加主服务器,能够减少负载,但是更新处理的冲突可能会造成数据的不一致,这样对于读写请求在应用服务器中需要进行判断分配给合适的主数据库。
2、如果增加cache(如Memcached),就需要考虑cache和数据库数据的一致性,保证数据库的更新能在很短的时间内反映到cache中。
3、写操作主要集中在主服务器上,主服务器无法承担负载压力后只能采用向上扩展方式,开销很大。
4、还可以将数据进行水平或垂直切分分布到多个节点,但代价同样很高,同时会引入分布式事务以及跨节点的join、排序操作(跨节点的join请求会耗费大量的网络资源,如果在应用层进行整合,则会加重应用层的负担)

  • 难以支持高并发读写

为保障可用性,数据通常保存副本。
关系数据库本质上支持事务,那么就要保证ACID特性中的原子性和一致性,因此数据的更新必须在所有副本间同步,会带来一定的延迟。
只有极个别云中的关系数据库也支持读副本(Amazon RDS MySQL),允许副本间数据不一致,但这种副本无法在主副本故障时,替代主副本,仍然需要存在同步备份的副本。

缺点(整合2)

  • 不适合在分布式环境中的向外扩展
  • 所有的应用服务器都共享一个中心的数据库服务器
  • 难以支持高并发读写
  • 不擅长进行大量数据的写入处理
  • 对于字段不固定的应用无法进行表结构的变更及建立索引
  • 对简单查询需要快速返回结果的处理效率较低

总结:
关系型数据库在大量数据的写入处理表结构变更及建立索引字段不固定的应用对简单查询需要快速返回结果的处理方面存在不足

NoSQL的优点

  • 易于数据的分散
  • 提升性能和增大规模
  • 模式自由
  • 扩展性好

典型的NoSQL类型

存储类型代表解决方案特点
列存储HBase按列存储,适用于数据压缩,对一个或几个字段进行查询的效率很高
文档存储MongoDB保证海量数据存储的同时,具有良好的查询性能,用类Json格式进行存储
Key-Value存储Redis(永久性和临时性兼具)、MemcacheDB(临时性键值存储)具有极高的并发读写性能。通过key迅速查找到value,但只能通过key查询
图数据库Neo4J图形关系的最佳存储模式
对象数据库db4o,Versant类似面向对象语言的语法操作数据库,通过对象的方式存取数据
xml数据库BaseX、Berkerey DB XML高效存储XML数据,并支持XML的内部查询语法

NoSQL类型解释

键值存储

即抛弃了表的概念,所有的数据都以键值对的形式存储(这样的话,不支持模糊查询),具体的存储方法,分为临时性永久性两者兼具三种。

键值存储支持键上自有的隐形索引,但键值存储一般不支持事务处理机制。

很关键的一点是:键值存储引擎并不在意“值”的内部结构,一个值上可以存储任意信息(可以是一个xml文档,一个json对象,或者其他任意序列化形式),它依赖客户端对“值”进行解释和管理


临时性键值存储
即所有数据保存在内存中,服务退出时数据丢失

优点是存取速度非常快,理论上最快

永久性键值存储:
即将数据存储在磁盘上,(学过操作系统的应该知道,这是相对永久,仍然需要各种容灾处理)

而Redis则是两者兼具,其既在内存中存储,又定时根据数据的变动速度,动态的将数据存储到磁盘中。


基于文档的数据库

如MongoDB,这种存储没有强制的架构,同时支持嵌套类型,如楼中楼的多层回复等,存储方式一般是基于json字符串、xml文档或是某些类似的能够嵌套的文档结构。

和键值存储一样,该种存储方式不需要定义表结构,但是可以像关系数据库一样使用复杂的查询来查找内容,这是键值存储不具备的。

和键值存储不同的是,文档存储关心文档的内部结构,因此文档存储支持二级索引,从而可以对任意字段进行高效查询。

为了便于管理数据,应用对要检索的数据采取一些约定,或者利用存储引擎的能力将不同的文档划分成不同的集合。

面向列的数据库

列式存储以流的方式在列中存储所有的数据。对于任何记录,索引都可以快速地获取列上的数据。

如HBASE,这种数据库比较适合处理海量高维的(稀疏)数据,复杂的数据更适合存储在列式数据库中。列式数据库也支持行检索,但也是通过从每个列获取匹配的列值重新组成列的方式进行的。

课堂上的一个例子是,为了做人物画像,需要一个人在医院的所有购药的药物种类的记录,一个人只会有几种或者十几种的购药记录,但药物种类有几十万种,如果以一个人为一行数据的话,使用关系型数据库会有很大的开销,这样就需要面向列的数据库来应对。

数据一致性理论

数据一致性

强一致性

解释:假如A先写入了一个值到存储系统,存储系统保证后续A,B,C的读取操作都将返回最新值

注意:单副本数据容易保证强一致性;多副本数据需要使用分布式事务协议

也叫即时一致性

弱一致性

假如A先写入了一个值到存储系统,存储系统不能保证后续A,B,C的读取操作能读取到最新值

不一致性窗口(区间):从A写入到后续操作A,B,C读取到最新值这一段时间

注意:弱一致性不保证可以读到最新的数据值,即使过了不一致性窗口也可能读不到

最终一致性

最终一致性是弱一致性的一种特例

假如A先写了一个值到存储系统,存储系统保证如果在A,B,C后续读取之前没有其它写操作更新同样的值的话,最终所有的读取操作都会读取到A写入的最新值

不一致性窗口”的区间和弱一致性相同,且其大小依赖于以下的几个因素(如果没有失败产生):

  • 交互延迟
  • 系统的负载
  • 以及复制技术中replica的个数(这个可以理解为master/slave模式中,slave的个数)

最终一致性方面最出名的系统可以说是DNS系统,当更新一个域名的IP以后,根据配置策略以及缓存控制策略的不同,最终所有的客户都会看到最新的值

在这里插入图片描述

其他一致性

因果一致性(Causal consistency):如果A通知B它已经更新了数据,那么B的后续读取操作则读取A写入的最新值,而与A没有因果关系的C则可以最终一致性

读自写一致性(Read-your-writes consistency):如果A写入了最新的值,那么A的后续操作都会读取到最新值。但是其它用户可能要过一会才可以看到

会话一致性(Session consistency):此种一致性要求客户端和存储系统交互的整个会话阶段保证Read-your-writes consistency,Hibernate的session提供的一致性保证就属于此种一致性

单调读一致性(Monotonic read consistency):此种一致性要求如果A已经读取了对象的某个值,那么后续操作将不会读取到更早的值

单调写一致性(Monotonic write consistency):此种一致性保证系统会序列化执行一个进程中的所有写操作

CAP理论

一个分布式系统不可能满足一致性,可用性和分区容错性这三个需求,最多只能同时满足两个

  • C:Consistency 一致性:数据一致更新,所有数据变动都是同步的(所有节点访问同一份最新的数据副本)
  • A:Availability 可用性:某个节点的宕机不会影响其他节点继续完成操作
  • P:Tolerance of network Partition 分区容忍性:能容忍网络分区

CAP理论的应用实例

在这里插入图片描述

BASE理论

核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。BASE模型完全不同于ACID的强一致性模型,主要用于NoSQL,牺牲高一致性,获得可用性或可靠性

  • Basically Availble 基本可用:支持分区失败(e.g. sharding碎片划分数据库)

  • Soft-state 软状态/柔性事务:状态可以有一段时间不同步,异步。

  • Eventural Consistency 最终一致性:最终数据是一致的就可以了,而不是时时高一致。

如刷新视频,会出现新的视频,但追加的数据不同(最终会相同–最终一致性)

关系数据库的ACID理论(回顾对比用)

高一致性 + 可用性 很难进行分区

  • Atomicity 原子性:一个事务中所有操作都必须全部完成,要么全部不完成。
  • Consistency 一致性: 在事务开始或结束时,数据库应该在一致状态。
  • Isolation 隔离性:事务将假定只有它自己在操作数据库,彼此不知晓。
  • Durability 持久性:一旦事务完成,就不能返回。

数据一致性实现技术

NWR模型

根据CAP理论,一致性,可用性和分区容错性最多只能满足两个,因此需要在一致性和可用性之间做一平衡
NWR模型是Amazon分布式存储引擎Dynamo中使用的技术,将CAP的选择权交给了用户,让用户自己选择CAP中的哪两个。

NWR模型中:(下文中备份也可以理解为节点)

  • N = N个备份,即复制的节点数量
  • R = 至少读取R个备份(成功读操作的最小节点数)
  • W = 要写入至少W份才认为成功(成功写操作的最小节点数)
  • 只需要W+R > N,就可以保证强一致性

在分布式系统中,一般都要有容错性,所以一般N>3

W+R > N, 所以 R > N-W
所以读取的份数一定要比总备份数减去确保写成功的节点的差值要大。根据抽屉原理(是吧?),这个时候的读操作,肯定会读到一个最新的写操作。

优化写性能(写多读少)
配置W=1,N=R
这样,写完一个副本就成功,其他的副本异步复制即可;而R=N,那么读取数据的时候需要读全部节点的数据,(这个时候可能会出现数据冲突,需要用户自行判断冲突数据)。

优化读性能(读多写少)
配置 W=N,R=1
这时,写完所有的副本才算成功,而读的时候只需读一个副本即可(只能保证读任意节点都一致,不能保证是最新,此时可能还没有写成功?)。

应用:如使用NoSQL做cache等业务的时候(只要写好了就可以读)?

平衡读写性能
W = Q, R = Q where Q = N / 2 + 1 一般应用适用,读写性能之间取得平衡,如N=3,W=2,R=2

单机版
当数据不多,单台能搞定,且不需要容错和扩展性的时候,可以配置N=1(只有一份数据),根据公式W+R>N,则W=1,R=1。这种情况就简化为单机问题了。


NWR补充内容(用于加深理解)

NWR模型的一些设置会造成脏数据的问题,可能每次的读写操作都不在同一个结点上,于是会出现一些结点上的数据并不是最新版本,但却进行了最新的操作。

所以,Amazon Dynamo引了数据版本的设计。也就是说,如果你读出来数据的版本是v1,当你计算完成后要回填数据后,却发现数据的版本号已经被人更新成了v2,那么服务器就会拒绝你。版本这个事就像“乐观锁”一样。

但是,对于分布式和NWR模型来说,版本也会有恶梦的时候——就是版本冲的问题,比如:我们设置了N=3 W=1,如果A结点上接受了一个值,版本由v1 -> v2,但还没有来得及同步到结点B上(异步的,应该W=1,写一份就算成功),B结点上还是v1版本,此时,B结点接到写请求,按道理来说,他需要拒绝掉,但是他一方面并不知道别的结点已经被更新到v2,另一方面他也无法拒绝,因为W=1,所以写一分就成功了。于是,出现了严重的版本冲突。

Amazon的Dynamo把版本冲突这个问题巧妙地回避掉了——版本冲这个事交给用户自己来处理。

于是,Dynamo引入了Vector Clock(矢量钟?!)这个设计。这个设计让每个结点各自记录自己的版本信息,也就是说,对于同一个数据,需要记录两个事:1)谁更新的我,2)我的版本号是什么。

下面,我们来看一个操作序列:

1)一个写请求,第一次被节点A处理了。节点A会增加一个版本信息(A,1)。我们把这个时候的数据记做D1(A,1)。 然后另外一个对同样key的请求还是被A处理了于是有D2(A,2)。这个时候,D2是可以覆盖D1的,不会有冲突产生。

2)现在我们假设D2传播到了所有节点(B和C),B和C收到的数据不是从客户产生的,而是别人复制给他们的,所以他们不产生新的版本信息,所以现在B和C所持有的数据还是D2(A,2)。于是A,B,C上的数据及其版本号都是一样的。

3)如果我们有一个新的写请求到了B结点上,于是B结点生成数据D3(A,2; B,1),意思是:数据D全局版本号为3,A升了两新,B升了一次。这不就是所谓的代码版本的log么?

4)如果D3没有传播到C的时候又一个请求被C处理了,于是,以C结点上的数据是D4(A,2; C,1)。

5)好,最精彩的事情来了:如果这个时候来了一个读请求,我们要记得,我们的W=1 那么R=N=3,所以R会从所有三个节点上读,此时,他会读到三个版本:

A结点:D2(A,2)
B结点:D3(A,2; ?B,1);
C结点:D4(A,2; ?C,1)
6)这个时候可以判断出,D2已经是旧版本(已经包含在D3/D4中),可以舍弃。

7)但是D3和D4是明显的版本冲突。于是,交给调用方自己去做版本冲突处理。就像源代码版本管理一样。

很明显,上述的Dynamo的配置用的是CAP里的A和P。


两阶段提交协议

在分布式系统中,每个节点只能知道自己的操作是否成功,不能知道其他节点操作是否成功。因此,当一个事务跨越多个节点时(多个节点都有操作),为了保持事务的ACID特性,需要引入一个协调者来统一掌控所有节点(参与者) 的操作结果并最终反馈给这些节点是否进行提交。

二阶段提交(Two-phaseCommit) 是指,在计算机网络以及数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务提交时保持一致性而设计的一种算法(Algorithm)。

算法描述

参与者将操作成败通知协调者,再由协调者根据所有参与者的反馈情报决定各参与者是否要提交操作还是中止操作。

两个阶段

  • 第一阶段: 准备阶段(投票阶段)
  • 第二阶段: 提交阶段(执行阶段)。

准备阶段

以一个协调者三个参与者为例

  • 协调者向三个参与者分别发送请求提交请求,等待参与者应答/
  • 请求提交请求中包含了要执行的操作,参与者如果可以执行,就执行协调者发起的事务操作,写日志,并返回,如果因为某些原因不能执行或者执行失败,就返回

提交阶段

  • 协调者接收参与者返回的消息
  • 如果均为,协调者向三个参与者发送提交请求,等待所有参与者完成提交、释放所有事务处理过程中使用的锁资源、返回完成消息后,完成事务
  • 如果有一个以上为,则协调者向三个参与者发送回滚请求,等待所有参与者完成回滚应答ACK回滚完成消息后,取消事务

在这里插入图片描述

优缺点

优点:实现简单
缺点:

  • 同步阻塞:执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。
  • 单点故障:由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)
  • 数据不一致:在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象
  • 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值