nosql理论笔记(1)
这几天在网上看了很多关于nosql的资料,有必要写写自己的理解。
nosql现在很多时候是指kv存储,作为缓存使用,用在业务和数据库中间,真正保证数据安全还是要在数据库做。把nosql和kv存储等同是不对的,nosql还可以做很多东西,叫做分布式存储比较适合。
由于有google的gfs+bigtable和Amazon的dynamo论文的影响,现在基本上的nosql实现都可以分成这两类。gfs+bigtable是有中心节点控制的,而dynamo是去中心化的,每一个节点都是平等的,任何一个节点失败宕机都不会影响整个系统
GFS
gfs是google部署在廉价机器上的大型分布式文件系统,bigtable架构于gfs之上。
gfs分成master server和chunk server,master server维护系统的元数据,chunk server存储文件数据,当客户端获取文件数据的时候直接和chunk server通信,只有在元数据发生变化的时候,客户端才和master通信获得元数据缓存在客户端,所以master server在整个系统中至关重要,如果master宕机了整个系统就不能用了,所以master肯定是有备份的,这个后面再说。
在chunk server中文件被分成固定大小的chunk,在Chunk创建的时候(默认64M),Master服务器会给每个Chunk分配一个不变的、全球唯一的64位的Chunk标识。文件是以linux普通文件形式存放于硬盘之中。每个chunk在不同机器之间备份了多份,默认份数为3。
master server维护系统的元数据,包括三个部分:文件和chunk的命名空间(文件比chunk大或者小都有可能,所以需要单独命名),文件到chunk的映射,chunk副本的位置信息。第三类信息会在Master服务器启动时,或者有新的Chunk服务器加入时,向各个Chunk服务器轮询它们所存储的Chunk的信息。
除此之外master server对整个文件系统进行全局控制,如chunk server的租约管理,chunk复制,垃圾回收等。master和客户端还有心跳,这样在chunk server宕机后,客户端还能从master及时的得到最新的chunk server的元数据。整体的架构如下:
GFS的几个关键点
1.单一的Master server。
单一的Master server可以简化架构,成为一个中心点,系统的其他部分可以都来依赖这个中心点,但是当这个中心点不能提供服务的时候会使得整个系统不能服务,这也是很多分布式系统实现当中想去掉的部分。回头想想,数据库其实也是个中心点,数据库所在的机器可能也会出现故障 ,那么数据库也不是百分百的可靠,所以数据库的HA,主备复制,记录操作日志已备系统恢复回放操作都是可以使用在nosql中的,GFS中Master也使用了类似的机制
Master server有一台实时的热备,当修改元数据的时候,Master server先写操作日志,然后在修改内存当中的数据,master把所有的元数据放在内存当中,而且日志会同步到热备机器,当本机和热备机器的操作日志修改完成以后才回给客户端返回成功的消息,这样在宕机后切换到热备master就可以通过日志回放来构建元数据在内存中的结构,一般Master只持久化前两种元数据,后面一种在master启动的时候可以轮询chunck server得到,为了缩短回放的时间,日志到一定程度大小就会被做成检查点,这样只需要回复检查点之后的日志就可以了。
2.chunk server。
chunk大小默认是64M,在一个chunk不能放下数据的时候才会再创建一个chunk,这样不会太浪费空间。块尺寸大有几个重要的好处。它减少了客户端和主服务器通讯,对同一个块的读写,只需要一次用于获得块位置信息的与Master的通讯。明显的减小了通讯的压力。
为了在chunk server宕机的时候,文件的读写不会受到影响,一个文件会在不同的机器上面有多个副本,这样在一次写入的过程当中会涉及到多个chunk server。GFS文件的写入都是以文件追加的方式实现的,这样在一致性方面的实现难度会小很多。
涉及到多个chunk server的话肯定需要一个主的server先进行更新,然后一步步的传递个其他的server进行更新,如果客户端追加的时候每次都要询问先更新哪一台chunk,这样master会成为性能的瓶颈,于是GFS有了Lease机制,GFS系统中通过Lease机制将chunk写操作授权给Chunk Server,获取Lease授权的Chunk Server称为Primary Chunk Server,其它副本所在的Chunk Server称为Secondary Chunk Server。Lease授权针对单个chunk,在Lease有效期内,对该chunk的写操作都有Primary Chunk Server负责,从而减少Master的负担。其次Primary server选择对块所有操作的一系列顺序,所有的Secondary server都要遵循这个顺序,在租约快过期的时候,如果文件更新没有异常的话,master会延长他的租期,两者通过心跳通讯,即使master和Primary失去联系,master仍旧在老租约到期后产生一个加诸于其他的副本的租约。
GFS通过对每个chunk维护一个版本号来解决文件太老的问题,当master延长或者新建一个Lease,那么版本号会增加1,当一台chunk server宕机回复后,此时如果在这个机器上面的文件在其他机器上面的副本有更新,那么这个机器的文件版本比其他机器上低就会被垃圾回收掉。(这是因为在写的过程中,没有成功,认为是异常,Primary的lease肯定回收,选择Primary和其他Secondary进行写会是一个新的Lease,版本号就增加了)
GFS使用追加实现修改和新增数据,一次追加的过程如下:
- 客户端向Master请求chunk每个副本所在的Chunk Server,其中Primary Chunk Server持有修改Lease。如果没有Chunk Server持有Lease,说明该chunk最近没有写操作,Master会发起一个任务,按照一定的策略将chunk的Lease授权给其中一台chunk Server。
- Master返回客户端Primary和其它Chunk Server的位置信息,客户端将缓存这些信息供以后使用。如果不出现故障以及chunk server宕机写入失败导致Parimary Lease失效,或者Parimary宕机,那么这个信息就一直可以用。
- 客户端将要追加的记录发送到每一个副本。每一个Chunk Server会在内部的LRU结构中缓存这些数据。GFS中采用数据流和控制流分离的方法,从而能够基于网络拓扑结构更好地调度数据流的传输。
- 当所有副本都确认收到了数据,客户端发起一个写请求控制命令给Primary。由于Primary可能收到多个客户端对同一个chunk的并发追加操作,Primary将确定这些操作的顺序并写入本地;
- Primary把写请求提交给所有的Secondary副本。每一个Secondary会根据Primary确定的顺序执行写操作;
- Secondary副本成功完成后应答Primary;
- Primary应答客户端,如果有副本发生错误,将出现Primary写成功但是某些Secondary不成功的情况,客户端将重试3到7步骤。
依照前面所说的步骤,在正常情况下面一起还好说,所有副本都是强一致性的,但是分布式系统的一个出发点考虑就是单台机器是一定会出错的,那么有可能的在第6和第7步出错时部分chunk server写成功,部分写出错,然后进行重试,这样的结果是之前成功的server的数据是多份的,而失败的server如果在写过程中没有恢复数据就是没有的,起来了数据份数是一或者多份(前面说过GFS的数据都是追加模式,这样的好处是当有异常时,读到的数据可能是过期的,但不会是修改了的不正确的数据),所以GFS有一个一致性的模型。
3.一致性模型
当写入是在并发和有错误的情况下,造成不一致的情况是肯定的,GFS中定义了两个概念:一致性和已定义
一致性是指客户端不论从哪个chunk server进行读,读到的数据都是一样的,而已定义是指在操作数据后,是一致性的而且客户端能看到此次操作写入了什么数据。这样的话,串行写入是已定义,并行写入是一致但是未定义,对于追加操作,是已定义的但是部分不一致(部分chunk server没有写入成功)。
记录追加至少可以把数据(记录)原子性的追加到文件中一次。偏移位置被返回给客户端,用来标明包含记录的已定义范围的起点。GFS客户端追加失败将重试,只要返回用户追加成功,说明在所有副本中都至少追加成功了一次,那么有些server的数据重复问题需要应用程序来解决,而且失败重试的机器在文件数据之间可能有些填充数据,但是这个保证了前面所说的文件已定义,只需要处理部分不一致就可以了
4.快照
快照可以在以后用于恢复数据,快照使用copy-on-write技术,当master收到快照请求,取消所有chunk server的Lease,这样对这些server的数据追加就需要找新的Lease,这样才有可能在得到新的Lease的情况下写到新的文件。
当Lease回收后,Master把这些操作持久化到日志当中,然后复制源数据或者元数据的方式把日志回放到内存当中,新文件和源文件指向相同的地址,当有一个新的追加数据的请求,发现他操作的chunk的引用计数超过1,那么说明现在快照需求,转而指向新块,其他的chunk server也会这么做,以后数据的追加就在新块上面了。
5 . chunk sever的容错和负载均衡
每一个Chunk有多个存储副本,分别存储在不同的Chunk Server上。对于每一个Chunk,必须将所有的副本全部写入成功,才视为成功写入。如果相关的副本出现丢失或不可恢复的情况,Master自动将给副本复制到其它Chunk Server,从而确保副本保持一定的个数。
由于需要容错,那么就是负载均衡的一个原因了,其他原因可能是chunk server可能会分布不均。当Master创建了一个chunk,它会根据如下因素来选择chunk副本的初始位置:(1) 新副本所在的Chunk Server的磁盘利用率低于平均水平;(2) 限制每个Chunk Server”最近”创建的数量。(3)每个chunk的所有副本不能在同一个机架。第二点容易忽略但却很重要,因为创建完chunk以后通常需要马上写入数据,如果不限制”最近”创建的数量,当一台空的Chunk Server上线时,由于磁盘利用率低,可能导致大量的chunk瞬间迁移到这台机器从而将它压垮。
当Chunk的副本数量小于一定的数量后,Master会尝试重新复制一个chunk副本。可能的原因包括Chunk Server宕机或者Chunk Server报告自己的副本损坏,或者用户动态增加了Chunk的副本数。而复制是有优先级顺序的,比如副本完好的个数少了优先级高,阻塞了客户端的chunk优先级高,活着的chunk比最近删除的chunk优先级高。这些结果都是Master定期扫描当前副本的分布情况得来了的,master会在后台有单独的线程处理这些。
6 .垃圾回收
GFS采用延迟删除的机制,也就是说,当文件被删除后,GFS并不要求立即归还可用的物理存储,而是在元数据中将文件改名为一个隐藏的名字,并且包含一个删除时间戳。Master定时检查,如果发现文件删除超过一段时间(默认为3天,可配置),那么它会把文件从内存元数据中删除,以后Chunk Server和Master的心跳消息中,每一个Chunk Server都将报告自己的chunk集合,Master会回复在Master元数据中已经不存在的chunk信息,这时,Chunk Server会释放这些Chunk副本。为了减轻系统的负载,垃圾回收一般在服务低峰期执行。
另外,Chunk副本可能会因为Chunk Server失效期间丢失了对Chunk的修改操作而导致过期。系统对每个Chunk都维护了版本号,过期的Chunk可以通过版本号检测出来。Master仍然通过正常的垃圾回收机制来删除过期的副本。
分布式系统认为单机肯定会出现问题,所以做的很大一部分工作是保证在单机出现问题的情况下面数据的完整性,一致性,当然出现问题后可以有新的机器加入,那么原来的数据就有转移和复制的步骤,机器修复重新加入,那么需要从日志回放操作以及从其他机器恢复失效期间的数据。还有数据删除,回收空间等问题。中心单点备份问题等等