您的位置:首页 > 数据库

nosql理论笔记(2)

2011-11-18 16:40 281 查看
Bigtable是架在GFS上面的分布式结构化数据存储系统,在底层的存储方面依赖GFS的实现,Bigtable在享用GFS的同时,必须处理GFS带来的一些问题:GFS存储数据在异常的时候可能面临已定义但是部分不一致的情况,就是一部分数据在某个机器上面是多份的,在某个机器上只有一份+填充的数据,所以Bigtable必须解决这种问题。

数据模型

Bigtable是一个稀疏的、分布式的、持久化存储的多维度排序Map,Map的索引是行关键字、列关键字以及时间戳,Map中的每个value都是一个未经解析的byte数组。时间戳可以当做版本号来使用:

(row:string, column:string,time:int64)->string

这个我理解了很长时间,开始的时候拿着和数据库行存储的模式进行对比,数据库是按行进行存储的,所以当要查到一个列下面的某些数据时,就需要查询所有的行,取得符合的行然后扣出这个列数据,当然数据库可以对这个列建立索引,在另外一块地址上面对这个列进行排序,形成一个列序号对列实际地址的映射的B+树或者直接就是数据的B+树,这样查询的话,就直接查找B+树了。

之前在没有看论文之前,一直认为Bigtable是按列存储的,看了论文后发现他还是按行存储的,只不过是按照行关键字进行排序存储(行关键字可以认为是map的key)。Bigtable和数据库不同的是数据库的表的列数固定的(除非干涉改动),即使某条记录的某个列的数据是不存在的也是存储个空值,而Bigtable的列是很自由的,一条行记录和另外一条行记录的列可以完全的不同,这样的自由度就好多了。

行还是动态分区和负载均衡的最小单位,对于行关键字相同或者排序后很接近的,会存储在相邻的地址位置上面,这样存储的好处是当基于行查询时通讯的次数很少。分区就叫做Tablet。

列关键字组成的集合叫做“列族“,列族是访问控制的基本单位。存放在同一列族下的所有数据通常都属于同一个类型。列族在使用之前必须先创建,然后才能在列族中任何的列关键字下存放数据;一张表中的列族不能太多(最多几百个),并且列族在运行期间很少改变。但是列创建是没有限制的。

列一般的组成方式是:列族:限定词,这让我想到了面向对象编程当中一个类下面有很多的属性,创建对象后,各个对象的属性值是不一样的,这个属性的值可以认为是一个列所对应的值,如果person:firstname =mike;person:lastname=jordan,其中person是列族,person:firstname 和person:lastname是列。

时间戳可以当做数据的版本号,有些行列都相同,那么可以通过版本号决定需要哪一条数据。

Bigtable的组成

Bigtable主要有chubby分布式锁,Master tablet 和Data tablet构成。

和GFS一样,Bigtable也是中心节点的,Master tablet主要的任务就是:为data tablet服务器分配tablets、检测新加入的或者过期失效的data tablet服务器、对tablet服务器进行负载均衡、以及对保存在GFS上的文件进行垃圾收集。除此之外,它还处理对模式的相关修改操作,例如建立表和列族。当然Master tablet肯定是有热备的。每个Tablet服务器都管理一个Tablet的集合。每个Tablet服务器负责处理它所加载的Tablet的读写操作,以及在Tablets过大时,对其进行分割。

BigTable内部存储数据的文件是Google SSTable格式的。SSTable是一个持久化的、排序的、不可更改的Map,默认大小64KB,SSTable使用块索引(存储在SSTable的最后)来定位数据块。

BigTable依赖高可用的、序列化的分布式锁服务组件chubby,默认一个chubby服务包括了5个活动的副本,其中的一个副本被选为Master,并且处理请求。只有在大多数副本都是正常运行的,并且彼此之间能够互相通信的情况下,Chubby服务才是可用的。当有副本失效的时候,Chubby使用Paxos算法来保证副本的一致性,并且选择Master也是通过Paxos算法的。

Chubby提供了一个名字空间,里面包括了目录和小文件。每个目录或者文件可以当成一个锁,读写文件的操作都是原子的。每个客户端都维护一个与Chubby服务的会话。如果客户程序不能在租约到期的时间内重新签订会话的租约,这个会话就过期失效了。正是由于锁,Chubby可以在一个时间内制定一台Master Tablet。

他们的位置关系如下:



Master tablet的工作

前面可以看到,tablet是分层的,分成了Root tablet,Metadata tablet,data tablet,最多只有三层,主要读取个数据也不需要太多的查询和通讯。Master分配一个tablet给data tablet的时候,这个tablet在chubby中表明对这个tablet的独占锁,当这个data tablet宕机的时候,如果恢复后这个锁还没有被占有那么还是可以继续服务的,如果有新的机器加入并且获得了锁,那么原机器不能服务了,这一切是通过在chubby上面的文件锁和master指定新机器搞定的。当data tablet宕机,master发现了情况,删除这个文件锁,记录下没有被分配的tablet,当有机器上来时,Master创建文件,指定新机器获得锁,分配给新机器tablet,更新metadata tablet数据。这样可以保证tablet只会被一个data tablet持有。所以master启动的时候会有如下步骤:获得master的锁,保证只有一个master;扫描chubby,获得所有正在运行的tablet;扫描metadata tablet,获得所有tablet;去除正在运行的tablet,就是待分配的了,最后master指导分配。

操作tablet

修改tablet同样是先修改日志,然后在执行操作,操作tablet是先把操作保存在内存当中(memtable),到一定程度持久化成SStable,如下图所示:



所以数据的检索memtable+SStable的数据相加,不过一般都是排好序的,只要做文件的归并就可以了,当data tablet服务器宕机后,master指定另外一台,那么可以通过操作日志把memtable给恢复出来,这里可能会有一系列的检查点。

memtable会越来越大,到达阈值的时候,会持久化成SStable,这个过程叫做Minor Compaction,当SStable越来越多时(SStable是比较小的,从memtable而来就可以论证),数据检索需要归并的SStable会越来越多,这样速度上不去,所以SStable也会河边,这个叫做Major Compaction(这些概念像jvm的gc?)

还有一个问题就是tablet的分裂,因为tablet保持在一两百M的大小,大了就得分裂,bigtable的模型分裂还是很简单的,因为一个tablet在一个时刻只能是一个服务器持有,分裂成功后,需要更新metadata的的tablet的位置信息然后通知master,这样的话操作不是原子的,有可能后面出现错误,不过出现错误后master读到不对的位置时他会查询tablet的新信息的。

还有一个疑问是在看论文时,发现bigtable tablet的数据都是单份的,我想可能是GFS保证了数据的副本吧.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: