当今信息化时代充斥着大量的数据。海量数据存储是一个必然的趋势。然而数据如何的存储和查询,尤其是当今非结构化数据的快速增长,对其数据的存储,处理,查询。使得如今的 关系数据库存储带来了巨大的挑战。分布存储技巧是云计算的根基,主要研究如何存储、组织和管理数据中心上的大规模海量数据.由于面临的数据规模和用户规模更加庞大,在可扩展性、容错性以及成本控制方面面临着更加严峻的挑战[1]。
对于大量的半结构化数据(semi-structure data)和非结构化数据,,对其存储和并发计算以及扩展能力而设计出了NoSQL,像有google的Bigtable,Amaze 的Dynamo,以及Apache的Hbase。NoSQL支持强大的水平扩展能力和高性能,与关系数据库不同的是,NoSQL可以采用松弛一致性(relax consistant),但是供给最终一致性保证数据的读的不一致。像在Dynamo中为了供给高的写的能力(购物时不会因为并发而不会添加购物车不能成功,而影响用户体验),不得不采取最终一致性。根据CAP原理,一致性、高可用性、分区容忍性(Partition-tolerance)三者中最多择其二,舍其一。在Dynamo牺牲了一致性,但是供给高的可用性[6]。另外Dynamo采用非集中化管理,使得每个节点都是同等地位,充分利用分布式哈希表(DHT)的一种实现即一致性哈希,使得Dynamo供给强大的可扩展性。Hbase可以说供给强的一致性,但是牺牲掉了一定的高可用性,比如存在单点故障,在当一个Regionserver出问题或失去联系时,需要master来重新部署原Regionserver下面的是Region到别的空闲的服务器下。这段时间无法与下面的Region联系。Hbase是Apache的*项目Hadoop的一个组成部分,hadoop是一种分布式系统根基架构。它可以充分利用集群的威力高速运算和存储。下面着重介绍Hbase。
一、非结构化数据存储结构
Hbase是Apache的*子项目,它的理念来自于Google的Bigtable。它是分布的、面向列的、多维的数据库系统,它供给高的容错性和可扩展性,它是建立HDFS(Hadoop分布式文件系统)之上。Hbase的表的每一行有行键(row key)和任意多的列(column)组成,其中多个列可以组成列族(column family)。每个数据单元(cell)可以拥有数据的多个版本(version),这个是使用时间戳来区分。所以Hbase是拥有map:(行键,列族:列,时间戳)对应一个值[2][7]。
Hbase是应用在分布式系统之中,他将大量的行分成行区域(Region),将化分后的区域分布到集群中去。Hbase与HDFS同样是使用master-slave结构,在Hbase中slave对应是Regionserver,负责管理master分下来的Rregion。同时master还负责负载平衡以及当Region出现错误时,master会收到Regionserver的请求消息,会重新分配到新的空闲的节点(这涉及到HLog)。
正如上所说,Hbase是面向列的存储,它在实际的物理存储器中是以列族的存储,所以在列族相同的会在存储在一起。在与面向行的关系数据库比较,这会节省了大量为空的属性。Hbase也是一种NoSQL,它不像关系数据库那样供给结构化查询语句来访问其中的数据。NoSQL是一种模式*(schema-free)的数据库,良好是设计会提升数据结构而不存在表的重写[3]。
Hbase的容错性不得不提到HDFS,HDFS是Hadoop 分布式文件系统,它可以部署在廉价的机器上,提高系统的容错性和高的吞吐量。HDFS分为一个Namenode和多个Datanode,Namenode管理文件系统的名字空间,它维护着文件系统树以及整个树内所有的文件和目录。Datanode存储着数据块,负责删除添加等操作。Hbase的文件被分为固定大小的块(默认的为64M),块服务器是存储块和对指定块的读写操作。在分布式的集群中,机器故障乃是常态,为了安全问题,所以不断的检测机器的状况和数据的备份时必须的。HDFS的副本一般的情况下分为3份,一份是同个节点中,第二份放在不在机架上的另一个节点,最后一份是放在第二份相同机架的不同节点中[4]。Master存储着文件系统元数据(metadata),主要分为3种元数据:文件和块的名字空间、文件到块的映射和块副本的位置。块服务器存储着数据,所以master必要和块服务器保持者联系。Master定期发送心跳(heartbeat)与块服务器了解块服务器的状况。客户读写数据是都首先和master先取得联系然后再与块服务器完成读写操作。
在一致性上,HDFS 是一个松散的一致性检查的模型。他主要是为了追加(append)操作而不是覆盖重写(overwrite)操作。因为覆盖重写的话可能在一次读的操作会读到与其他副本不一致的数据,而在追加操作,其中一个副本的不一致也不会导致客户端读到不一致的数据。同时HDFS在追加操作时采用租用(Lease)机制,即将块的写操作授权给主块服务器(primary chunk server),另外的副本称为次块服务器(secondary chunk server)。当多个客户端的并发写操作时,主块服务器缓存其写的顺序,之后联系次服务器进行追加操作。从这里可以看出,在HDFS的根基之上供给版本一致性。而不同Dynamo采用矢量时钟即(节点,计数器)(node,counter)列表来钟捕捉同一不同版本的对象是否有因果关系。当客户端更新一个对象,它必须指定它正要更新哪个版本,当存在因果关系,直接覆盖之前的版本。若是两个独立的版本,更新其矢量时钟,使得存在多个版本。同事Dynamo采用了NRW机制(N: 复制的节点数量,R: 成功读操作的最小节点数,W: 成功写操作的最小节点数),当R+W>N时可以说明至少有一个版本是最新的版本,这样在数据的读操作就可以保证数据的一致性。[6]当然在这里也体现出了Dynamo的高可用行,比如设置W=1,即表明只要正确读入一个节点即可,不须保证写入的值全部传给副本。
二、非结构化数据的读写操作
对Hbase中数据的读写首先是根据行键值或行键值域(row key range)来检索,行键值是按照字典序排列的,针对同时访问的数据设计好相似的行键值会相应地减少I/O操作。上面提过,由于行区域到达一定大小时会分解并分布到集群中去,在Hbase中使用B+树来存储某个区域的位置信息。在树顶是root表,其保存META表的Region信息,并且root表只有一个,META表中存储着各个被划分的区域的信息,所以通过行健访问时首先访问root再一次访问META表。由此客户端访问数据需要经过多次的网络交互,所以客户端可以使用缓存来缓解。客户端是采用RPC机制与服务器端即master或RegionServer进行通信。另外Hbase还采用缓冲池来保持每次的连接,保证通信不必产生重新连接的时间开销。
客户端要求更新数据的时候,为了容错性,数据首先是HLog中,当HLog写成功是,之后数据是写入到menstore,当数据达到一定的大小时,数据会将内存刷新(flush)到本地磁盘中,形成存储文件(storefile),此时文件只是可读的。当存储文件的大小到达一定的大小,会进行合并(compact),这个合并将行键值相同的合并到一起形成一个比较大的存储文件,其过程是对版本的合并与删除的过程,所以从这个角度来看,Hbase是一个追加的过程。当然存储文件的大小到达一定的阀值时,会分裂(split)成两个存储文件[2]。存储文件在组织成HFile以块的形式存在底层的HDFS上。
在[5]中介绍Hbase作为HDFS上层的来评估在大规模数据中随机读和随机写的性能,文中是利用MySQL作为HDFS上层来存储与此作对比。结果显示在多用户多并发读和写时Hbase--HDFS组合负载表现更加的理想。
三、数据的搜索与查找法子探索
如今数据的以PB级别的,海量数据不断增长,怎样快速的存储以及搜索和查找指定的文件所需的时间问题。在关系数据库中,利用索引减少I/O次数来减少读指定的数据的时间,在Hbase中同样可以使用索引。
Hbase一般设置行键作为主键来查找数据,而行键是按照字典序排的,同时Hbase支持利用前缀来,所以合理利用行键会提高查找效率的。在[2]中提到二级索引(secondary index)解决不只是利用行键最为自己的主键,比如购物网站用户Hbase表的行键是用户ID,但是网站为了统计某个时间段的交易记载,在原来表的表上进行扫描可能会扫描整个表。为此我们可以设计另一张表,而这张表的主见是时间+用户,在Hbase进行按前缀扫描时,所需要的数据可能是放在同一块中,减少了I/O次数。
在[9]中是利用Hbase来存储来处理资源描述框架(RDF)的WEB数据,针对PDF的三元(triple)结构(S,P,O),其中该文章中S代表行键,P代表列,O代表单元(cell)的值。数据检索默认是按照行键值进行的,文章中建立了6个索引表( PSO, POS, SPO, SOP, OPS and OSP),这包含了所有行键与列的组合。当然这样做,会产生了数据的冗余,因为多建了5个索引。但是多出的索引满足多种查找。这也是二级索引的应用。
在[11]中利用Hadoop架构对半结构化数据和非结构化数据的存储、索引构建、数据查询的整体设计。
整体分为两个过程,第一步原始需要存储的数据经过Uploader形成Hbase面向列结构的表,下一步通过indexer形成对数据整理后的索引。第一步与第二步中中涉及到MapReduce操作,MapReduce是google提出的一种编程模型,是来处理大规模数据集的并行运算模型,它分为两个部分:map操作和reduce操作。Map操作将数据进行处理形成一个中间数据,且数据是(key,value)形式,reduce操作将map操作的结果作为输入数[8],即:
map (k1,v1) ——————> list(k2,v2)
reduce (k2,list(v2)) ————>list(v2)
其中在第一步中的MapReduce操作根据索引规则(index rule)进行操作(索引规则是利用半结构化数据或结构化数据的某种边界特征来分解原数据集)。客户端API可以通过index table进行对特定值或某个范围值进行检索。再从内容表(content table)中寻找指定的值。
在Hbase中为客户端供给一系列的API来访问数据,get(byte[] row)来获取指定的行对应的数据,然后实际上是客户端在指定的Region中收集到的行后在客户端来进一步执行。另外利用mapreduce虽然供给了强大的计算能力,但是它并不是在线业务的很好的方案。在[10]中提到一种协处理(Coprocessor)框架,它允许HBase 管理员在Region server中载入定制的代码,使的可以实现一些聚拢函数像行计数器、求最大值、最小值等。Coprocessor的机制可以理解为,Regionserver端添加了一些回调函数。客户端可以在多个节点调用并且可以并行执行。这样使得客户端不像以前那样请求到的数据在客户端进一步执行,而是请求在各个Region中并发执行后的结果直接返回给客户端,大大提高了效率。