HBase存储文件格式概述

转自:http://forchenyun.iteye.com/blog/828549

概述

HBase是基于Bigtable论文的面向列的分布式存储系统,其存储设计是基于Memtable/SSTable的。其它如Cassandra都是采用的该设计。

整个存储分为两部分,一部分为内存中的MemStore(Memtable),另外一部分为磁盘(这里是HDFS)上的HFile(SSTable)。下面分别讲述两种类型的存储分别的实现:

MemStore中最重要的变量是:

Java代码  
  1. volatile KeyValueSkipListSet kvset;  
volatile KeyValueSkipListSet kvset;

这里的KeyValueSkipListSet里面实际是这样的:

Java代码  
  1. private final ConcurrentNavigableMap<KeyValue, KeyValue> delegatee;  
private final ConcurrentNavigableMap<KeyValue, KeyValue> delegatee;

换句话说,其实就是一个放内存的Map存放着kv。

HFile是HBase实际的文件存储格式,它是基于TFile的文件格式,替换了早期的MapFile,改进了性能。

然后HBase会进行控制,当MemStore写满了以后进行刷磁盘操作。

而HLog是HBase的日志格式实现,主要是在写入的时候进行write-ahead-log,主要为recovery而做。

HFile

HFile是HBase中实际存数据的文件,为HBase提供高效快速的数据访问。它是基于Hadoop的TFile,模仿Google Bigtable 架构中的SSTable格式。之前的Hadoop的MapFiles已经被证明性能不能到达我们的期望。文件格式如下:

文件是变长的,唯一固定的块是File info和Trailer,如图所示,Trailer有指向其它块的指针,这些指针也写在了文件里,Index块记录了data和meta块的偏移量,data和meta块都是可选的。

块的大小是由表创建时的HColumnDescriptor指定的,如下是master web interface上看到的一个例子:

{NAME => 'docs', FAMILIES => [{NAME => 'cache', COMPRESSION => 'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'false'}, {NAME => 'contents', COMPRESSION => 'NONE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'false'}, ...

默认的大小是64KB,下面是一段关于HFile的解释:

“最小的块大小。我们建议通常将其设置为8KB到1MB之间,如果经常进行基于primary key的顺序访问,可以设置更大的块大小,但是这样会带来低效的随机访问效率(更多的数据需要被解压缩)。更小的块大小将带来更好的随机访问效率,但是会耗费更多的内存去维持索引,并且在创建的时候会比较慢,因为需要flush压缩流,这将导致一个FS I/O flush。由于内部的压缩codec的缓存,最小的块大小可以为20-30KB”

上图是HFile中每个KeyValue的格式,和普通的key-value没有太大的区别。

HLog

源码中的实现类是HLog。每个HRegionServer会对应一个HLog,HRegion在初始化的时候HRegionServer会将该HLog的实例作为构造函数传入其中。HLog的核心函数是其append()函数。

在HLog中,会维持一个Sequence Number,是一个AtomicLong型,当一个Region启动的时候会从HFile的Meta field里面读出当前的Sequence Number。





如图所示,由于HLog是Region之间共享的,因此,log的顺序是不定的,这一点后面会提到。当一个HRegionServer崩溃掉后,HMaster会让HRegionServer重启的时候根据日志进行恢复。

当前的WAL使用的是Hadoop下的SequenceFile格式,其key是HLogKey实例,它包括以下内容:

Java代码  
  1. private byte [] encodedRegionName;  
  2.   
  3. private byte [] tablename;  
  4.   
  5. private long logSeqNum;  
  6.   
  7. // Time at which this edit was written.  
  8.   
  9. private long writeTime;  
  10.   
  11. private byte clusterId;  
private byte [] encodedRegionName;



private byte [] tablename;



private long logSeqNum;



// Time at which this edit was written.



private long writeTime;



private byte clusterId;

由于操作系统处理批量的数据要块过单个单个的处理,因此,需要进行flush日志。LogFlusher实现了该功能,它调用了HLog.optionalSync(),它将检查是否到了hbase.regionserver.optionallogflushinterval,默认是10秒。

         日志的大小会有一个限制,这是用hbase.regionserver.logroll.period参数控制的,默认是1个小时。到点以后LogRoller会触发操作,检查当前的Sequence Number,看小于它的所有日志是否完整。

参考文献

http://www.larsgeorge.com/

主要参考自larsgeorge的hbase系列文章

你可能感兴趣的:(hbase)