欢迎大家来到IT世界,在知识的湖畔探索吧!
本文主要是介绍下HBase一些背景知识,希望通过这篇文章可以让大家对HBase的认识能有一个大致的轮廓。
在LSM之前,常用的有三种基本存储引擎,分别是
- 哈希
- B树
- LSM-Tree(Log-Structured Merge Tree)
哈希
哈希存储引擎是哈希表的持久化实现,支持增、删、改,以及随机读取操作,但不支持顺序扫描,对应的存储系统为键值(Key-Value)存储系统,如 Bitcask。它仅支持追加操作,删除也只是通过标识 value 为特殊值,通过定期合并(Compaction)实现垃圾回收。
B 树
B 树存储引擎是 B 树的持久化实现,不仅支持单条记录的增、删、读、改操作,还支持顺序扫描,对应的存储系统是关系数据库。关系数据库中通过索引访问数据,在 Mysql InnoDB 中,有一个称为聚集索引的东西,行的数据存于其中,组织成 B+ 树的结构。更多B系树的内容可以参考这里 。
重点是看LSM-Tree
LSM-Tree
图片来源lsm-tree论文。LSM-Tree原理把一棵大树拆分成N棵小树,它首先写入内存中,随着小树越来越大,内存中的小树会flush到磁盘中,磁盘中的树定期可以做merge操作,合并成一棵大树,以优化读性能。内存中树的一部分和磁盘中第一层树做merge,对于磁盘中的树直接做update操作有可能会破坏物理block的连续性,但是实际应用中,一般lsm有多层,当磁盘中的小树合并成一个大树的时候,可以重新排好顺序,使得写入block连续,优化读性能。
HBase存储引擎采用LSM-Tree架构,大体原理图如下
当RegionServer(RS)收到写请求的时候(write request),RS会将请求转至相应的Region。每一个Region都存储着一些列(a set of rows),根据其列族的不同,将这些列数据存储在相应的列族中(Column Family,简写CF)。不同的CFs中的数据存储在各自的HStore中,HStore由一个Memstore及一系列StoreFile组成(StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile)。Memstore位于RS的主内存中,而HFiles被写入到HDFS中。当RS处理写请求的时候,数据首先写入到Memstore,然后当Memstore到达一定的阀值的时候,Memstore中的数据会被flush到HFile中,当HFiles达到一定的阈值后,就会触发compact操作并执行删除文件操作。
补充:HBase存储引擎并没有采用通过Tree方式来实现有序存储,而是使用了Doug Lea大神的跳表ConcurrentSkipListMap(MemStore is a sorted ConcurrentSkipListMap)。
用到Memstore最主要的原因是:存储在HDFS上的数据需要按照row key排序。而HDFS本身被设计为顺序读写(sequential reads/writes),不允许修改。这样的话,HBase就不能够高效的写数据,因为要写入到HBase的数据不会被排序,这也就意味着没有为将来的检索优化。为了解决这个问题,HBase将最近接收到的数据缓存在内存中(in Memstore),在持久化到HDFS之前完成排序,然后再快速的顺序写入HDFS。需要注意的一点是实际的HFile中,不仅仅只是简单地排序的列数据的列表,下面会具体介绍HFileV2。
Hadoop自诞生伴随着SequenceFile格式,因此可以通过append key/value pairs存储文件,当正是因为hdfs append-only capability,因此被插入的file format是不允许被修改。如果你想查找一个特定的key,那么你必须的便利整个file直到找到这个key。
在这种情况下,你不得不去通过sequential read/write模式去处理。那么问题来了,像HBase要想去做random, low-latency read/write access那怎么玩?
补充:在早期HBase0.2.0之前版本中使用MapFile,详细看HBASE-61。
下面请看HFIle
HFile v1
在HBase0.2.0中,MapFile被替换成HFile,是一个为HBase数据存储的Map。HFile的idea来自MapFile,但是它比单纯的key/value file添加了更多的特性。比如,HFile添加了对metadata和index支持。
data blocks包含了和MapFile相同的key/value,对每个“block close operation” 操作,first key被添加到jindex,在HFile关闭时写入。
HFile文件格式添加了两个额外的“metadata” block types,即meta和FileInfo,这些两个key/value blocks在接近file关闭时写入。
Meta block被设计成保持大量数据,因此它的key类型是String,然而,FileInfo只是一个简单的Map,通过keys和values提供小量信息,因此key和values都是byte-array类型。ReginServers的StoreFile使用Meta-Blocks同存储Bloom Filter和FileInfo为支持Max SequenceId, Major compaction key and Timerange info。这些很好的优化避免在如下情况读文件。
- file没有变化(key不存在Boom Filter,如果开启了Boom Filter)
- file is too old(Max SequenceId)或者这个文件太新(Timerange)没有包含我们正在查找的key。
HFile v2
motivation
在regionserver中HFile format的large Bloom filters和block indexes导致消耗了大量的内存后和启动慢。每个HFile 100M,当超过20个regions时Bloom Filters增长到2GB,Block indexes增长到6GB。region会直到它的所有block index data加载完毕才会open。Large Bloom filters会产生可能的性能问题,第一次get请求需要查找Bloom filter会有潜在的可能性导致加载整个Bloom filter bit数组。
为了加速regionserver启动,于是将Bloom filters和block indexes分成成multiple blocks,并且在他们fill up时写进他们的blocks。这样可以减少HFile写内存的占用。在Bloom filter情况下,“filling up a block” 指累积到固定bit array大小的keys。现在称Bloom filter blocks and index blocks为“inline blocks”,“inline blocks”使用data blocks散列,与此同时,我们我再依赖block offsets的值推断data block长度(在v1版本中用block之间的block offset去推断data block长度)。
HFile被设计成low leve的文件存储格式,它不应该处理程序特定的细节,比如Bloom filters,它在StoreFile层次上被处理。因此,我们在HFile中叫Bloom filter为 “inline” blocks。我们也提供HFile的接口去写它们的inline blocks。
另外一个文件格式是通过使用contiguous “load-on-open” 加载打开HFile必须的部分,目的在于减少regionserver启动时间。目前,当HFile打开,会有独立的seek操作去读取trailer、data/meta和file info。有超过两个seek操作读取Bloom filter的“data”和“meta”部分,在v2,我们只需一次seek去读取trailer,然后再次从contiguous block去seek我们需要打开file的部分。
在HBase0.92中引入了HFile v2(HBASE-3857),对大量数据存储在性能上有很大的提升,主要问题是HFile v1需要在内存中加载所有的indexes和大量的Bloom Filters,在v2中引入multi-level indexes和block-level Bloom Filter。总而言之,HFile v2提升了在速度、内存和cache使用。
HFile v2主要特性是引入了Bloom filter blocks and index blocks被称为 “inline blocks”,通过这个来分裂每个block的index 和Bloom Filter,而不是在内存中加载所有的 index和Bloom Filter。通过这个方式,你可以加载你需要的。
因为index被移动到block层次,于是有了multi-level index,表示对每个block都有自己的index(leaf-index)。对每个block被保持并且被创建index作为multilevel-index b+tree。
现在在block header就添加一些信息,“Block Magic” 字段被替换为 “Block Type”,表示这个block是“Data”,Leaf-Index, Bloom, Metadata, Root-Index等等。当然, compressed、uncompressed size和offset prev block这三个字段也被添加用于快速的backward和forward seeks。看下overview图
HFile具体得文件格式包括7部分
- Unified version 2 block format
- Block index in version 2
- Root block index format in version 2
- Non-root block index format in version 2
- Bloom filters in version 2
- File Info format in versions 1 and 2
- Fixed file trailer format differences between versions 1 and 2
1.version 2版本每个block的data section都包含的字段
2.HFile version 2中有三种类型的block indexes,使用root and non-root两种方式存储
• Data index — version 2 multi-level block index, consisting of:
o Version 2 root index, stored in the data block index section of the file
o Optionally, version 2 intermediate levels, stored in the non-root format in the data index section of the file.
Intermediate levels can only be present if leaf level blocks are present.
o Optionally, version 2 leaf levels, stored in the non-root format inline with data blocks
• Meta index — version 2 root index format only, stored in the meta index section of the file
• Bloom index — version 2 root index format only, stored in the “load-on-open” section as part of Bloom filter metadata.
3.root index format
4.Non-root block index format
5.与version 1对比,version 2 HFile Bloom filter metadata被存储在HFile的load-on-open section提高启动速度。
6.File Info format in versions 1 and 2
hfile.LASTKEY The last key of the file (byte array)
hfile.AVG_KEY_LEN The average key length in the file (int)
hfile.AVG_VALUE_LEN The average value length in the file (int)
在version 2中,File info format没有改变,但是我们移动这个file info到文件的最后section,在HFile被opend时能被加载。同时,我们在verson 2 file info不再存储comparator,取而代之的是我们存储它到固定的trailer,这是因为当我们在解析HFile的load-on-open section时需要知道comparator。
7.Fixed file trailer format differences between versions 1 and 2
其中,Unified version 2 block format中存储数据keyvalue,format格式如下
大致分为三块,key/value length, key和value。
关于HFileV2详细设计文档可以看HBASE-3857
hbase hfile命令查看HFile文件
usage: HFile [-a] [-b] [-e] [-f | -r ] [-h] [-k] [-m] [-p]
[-s] [-v] [-w ]
-a,–checkfamily 开启family check
-b,–printblocks 打印block index meta data
-e,–printkey 只打印keys
-f,–file 按文件路径scan; e.g. hdfs://a:9000/hbase/hbase:meta/12/34
-h,–printblockheaders 打印每个block的header文件
-k,–checkrow Enable row order check; looks for out-of-order keys
-m,–printmeta 打印hfile的meta数据
-p,–printkv 打印keyvalue
-r,–region Region to scan. Pass region name; e.g. ‘hbase:meta,1’
-s,–stats 打印统计个数
-v,–verbose 详细模式,打印分隔符
-w,–seekToRow 搜索这个rowkey,并打印这个rowkey的所有keyvalue
1)打印hfile meta
bin/hbase hfile -m -h -f /dev_hbase/data/default/ycsb_basic/18d4f5fde73f4dda5f376b47ef/family/4a2c8ee46edc47f8a2310e22bb384d5c
2)打印hfile kv
bin/hbase hfile -k -f /dev_hbase/data/default/ycsb_basic/18d4f5fde73f4dda5f376b47ef/family/4a2c8ee46edc47f8a2310e22bb384d5c
3)打印meta表信息
bin/hbase hfile -p -f /hbase/data/hbase/meta//info/8fdd2e7beb0942d4bd84fb62a48dc028
其中
1)18d4f5fde73f4dda5f376b47ef就是encoded region;
2)family为Column Family;
3)4a2c8ee46edc47f8a2310e22bb384d5c为HFile。
参考
[1] https://en.wikipedia.org/wiki/Log-structured_merge-tree
[2] http://blog.cloudera.com/blog/2012/06/hbase-io-hfile-input-output/
[3] http://th30z.blogspot.com/2011/02/hbase-io-hfile.html?spref=tw
[4] http://blog.cloudera.com/blog/2012/06/hbase-write-path/
[5] https://sematext.com/blog/2012/07/16/hbase-memstore-what-you-should-know/
[6] https://issues.apache.org/jira/browse/HBASE-3857
[7] https://issues.apache.org/jira/browse/HBASE-1200
[8] https://www.quora.com/How-are-bloom-filters-used-in-HBase
[9] http://hbase.apache.org/book.html#keyvalue
[10] https://en.wikipedia.org/wiki/Java_ConcurrentMap
[11] http://cloudepr.blogspot.com/2009/09/hfile-block-indexed-file-format-to.html
[12] https://mapr.com/blog/in-depth-look-hbase-architecture/
文章来源:
https://oomspot.com/post/hbase-lsm
欢迎访问 开发者的技术家园 – OomSpot
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/83835.html