?
HBase中的所有數據文件都存儲在Hadoop HDFS文件系統上,主要包括兩種文件類型:
1.?HFile, HBase中KeyValue數據的存儲格式,HFile是Hadoop的二進制格式文件,實際上StoreFile就是對HFile做了輕量級包裝,即StoreFile底層就是HFile
2.?HLog File,HBase中WAL(Write Ahead Log) 的存儲格式,物理上是Hadoop的Sequence File
下面主要通過代碼理解一下HFile的存儲格式。
HFile
下圖是HFile的存儲格式:
HFile由6部分組成的,其中數據KeyValue保存在Block 0 … N中,其他部分的功能有:確定Block Index的起始位置;確定某個key所在的Block位置(如block index);判斷一個key是否在這個HFile中(如Meta Block保存了Bloom Filter信息)。具體代碼是在HFile.java中實現的,HFile內容是按照從上到下的順序寫入的(Data Block、Meta Block、File Info、Data Block Index、Meta Block Index、Fixed File Trailer)。
KeyValue: HFile里面的每個KeyValue對就是一個簡單的byte數組。但是這個byte數組里面包含了很多項,并且有固定的結構。我們來看看里面的具體結構:
開始是兩個固定長度的數值,分別表示Key的長度和Value的長度。緊接著是Key,開始是固定長度的數值,表示RowKey的長度,緊接著是 RowKey,然后是固定長度的數值,表示Family的長度,然后是Family,接著是Qualifier,然后是兩個固定長度的數值,表示Time Stamp和Key Type(Put/Delete)。Value部分沒有這么復雜的結構,就是純粹的二進制數據了。
Data Block: 由DATABLOCKMAGIC和若干個record組成,其中record就是一個KeyValue(key length, value length, key, value),默認大小是64k,小的數據塊有利于隨機讀操作,而大的數據塊則有利于scan操作,這是因為讀KeyValue的時候,HBase會將查詢到的data block全部讀到Lru Block Cache中去,而不是僅僅將這個record讀到cache中去。
private void append(final byte [] key, final int koffset, final int klength, final byte [] value, final int voffset, final int vlength) throws IOException {
this.out.writeInt(klength);
this.keylength += klength;
this.out.writeInt(vlength);
this.valuelength += vlength;
this.out.write(key, koffset, klength);
this.out.write(value, voffset, vlength);
}
Meta Block: 由METABLOCKMAGIC和Bloom Filter信息組成。
public void close() throws IOException {
if (metaNames.size() > 0) {
for (int i = 0 ; i < metaNames.size() ; ++ i ) {
dos.write( METABLOCKMAGIC );
metaData.get(i).write(dos);
}
}
}
File Info:? 由MapSize和若干個key/value,這里保存的是HFile的一些基本信息,如hfile.LASTKEY, hfile.AVG_KEY_LEN, hfile.AVG_VALUE_LEN, hfile.COMPARATOR。
private long writeFileInfo(FSDataOutputStream o) throws IOException {
if (this.lastKeyBuffer != null) {
// Make a copy.? The copy is stuffed into HMapWritable.? Needs a clean
// byte buffer.? Won’t take a tuple.
byte [] b = new byte[this.lastKeyLength];
System. arraycopy (this.lastKeyBuffer, this.lastKeyOffset, b, 0, this.lastKeyLength);
appendFileInfo (this.fileinfo, FileInfo. LASTKEY , b, false);
}
int avgKeyLen = this.entryCount == 0? 0: (int)(this.keylength/this.entryCount);
appendFileInfo (this.fileinfo, FileInfo. AVG_KEY_LEN , Bytes. toBytes (avgKeyLen), false);
int avgValueLen = this.entryCount == 0? 0: (int)(this.valuelength/this.entryCount);
appendFileInfo (this.fileinfo, FileInfo. AVG_VALUE_LEN ,
Bytes. toBytes (avgValueLen), false);
appendFileInfo (this.fileinfo, FileInfo. COMPARATOR , Bytes. toBytes (this.comparator.getClass().getName()), false);
long pos = o.getPos();
this.fileinfo.write(o);
return pos;
}
Data/Meta Block Index: ?由INDEXBLOCKMAGIC和若干個record組成,而每一個record由3個部分組成 — block的起始位置,block的大小,block中的第一個key。
static long writeIndex(final FSDataOutputStream o, final List<byte []> keys, final List<Long> offsets, final List<Integer> sizes) throws IOException {
long pos = o.getPos();
// Don’t write an index if nothing in the index.
if (keys.size() > 0) {
o.write( INDEXBLOCKMAGIC );
// Write the index.
for (int i = 0; i < keys.size(); ++i) {
o.writeLong(offsets.get(i).longValue());
o.writeInt(sizes.get(i).intValue());
byte [] key = keys.get(i);
Bytes. writeByteArray (o, key);
}
}
return pos;
}
Fixed file trailer: ?大小固定,主要是可以根據它查找到File Info, Block Index的起始位置。
public void close() throws IOException {
trailer.fileinfoOffset = writeFileInfo(this.outputStream);
trailer.dataIndexOffset = BlockIndex.writeIndex(this.outputStream,
this.blockKeys, this.blockOffsets, this.blockDataSizes);
if (metaNames.size() > 0) {
trailer.metaIndexOffset = BlockIndex.writeIndex(this.outputStream,
this.metaNames, metaOffsets, metaDataSizes);
}
trailer.dataIndexCount = blockKeys.size();
trailer.metaIndexCount = metaNames.size();
trailer.totalUncompressedBytes = totalBytes;
trailer.entryCount = entryCount;
trailer.compressionCodec = this.compressAlgo.ordinal();
trailer.serialize(outputStream);
}
注:上面的代碼剪切自HFile.java中的代碼,更多信息可以查看Hbase源代碼。
參考: http://www.searchtb.com/2011/01/understanding-hbase.html
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
