文件主要分為四個部分:Scanned block section,Non-scanned block section,Opening-time data section和Trailer。
無論是Data Block Index還是Bloom Filter,都采用了分層索引的設計。
Data Block的索引,在HFile V2中做多可支持三層索引:最底層的Data Block Index稱之為Leaf Index Block,可直接索引到Data Block;中間層稱之為Intermediate Index Block,最上層稱之為Root Data Index,Root Data index存放在壹個稱之為”Load-on-open Section“區域,Region Open時會被加載到內存中。基本的索引邏輯為:由Root Data Index索引到Intermediate Block Index,再由Intermediate Block Index索引到Leaf Index Block,最後由Leaf Index Block查找到對應的Data Block。在實際場景中,Intermediate Block Index基本上不會存在,文末部分會通過詳細的計算闡述它基本不存在的原因,因此,索引邏輯被簡化為:由Root Data Index直接索引到Leaf Index Block,再由Leaf Index Block查找到的對應的Data Block。
在”Scanned Block Section“區域,Data Block(存放用戶數據KeyValue)、存放Data Block索引的Leaf Index Block(存放Data Block的索引)與Bloom Block(Bloom Filter數據)交叉存在。
無論是Data Block的索引數據,還是Bloom Filter數據,都被拆成了多個Block,基於這樣的設計,無論是索引數據,還是Bloom Filter,都可以按需讀取,避免在Region Open階段或讀取階段壹次讀入大量的數據,有效降低時延。
至此,壹個完整的HFile已生成。我們可以通過下圖再簡單回顧壹下Root Index Block、Leaf Index Block、Data Block所處的位置以及索引關系:
Bloom Filter包含Bloom元數據(Hash函數類型,Hash函數個數等)與 位圖數據(BloomData) ,為了避免每壹次讀取時加載所有的Bloom Data,HFile V2中 將BloomData部分分成了多個小的Bloom Block 。BloomData數據也被當成壹類Inline Block,與Data Block、Leaf Index Block交叉存在,而關於Bloom Filter的元數據與多個Bloom Block的索引信息,被存放在Load-On-Open Section部分。但需要註意的是,在FileInfo部分,保存了關於BloomFilter配置類型信息,***包含三種類型:不啟用,基於Row構建BloomFilter,基於Row+Column構建Bloom Filter。混合了BloomFilter Block以後的HFile構成如下圖所示:
再來看hbase如何在hdfs上去檢索壹行數據。首先要只要hbase的檢索都是以rowkey值或者rowkey值範圍來檢索數據的,現在root表中檢索mata表的的hregion位置,root表只會有壹個region而且永遠不會
被拆分以保證能夠壹次獲取到mata表的hregion的位置,在mata表中保存所有的用戶表的region的信息,region的rowkey有該region對應的表和第壹行的rowkey等組成,因為壹個表的rowkey在所有的
region上都是有序的字典排序,所有要檢索壹個rowkey只要通過對比mata表中region的rowkey就可以知道包含改rowkey的數據在那個region上,meta中還包含了region所咋的hregionserver的信息,通過
mata中的region的信息可以直接定位到包含改rowkey數據的所在的region在哪臺hregionserver上。
知道region在哪臺hregionserver上對已快速定位rowkey的數據還是不夠的,region會根據families把數據才分成store,壹個store只能包含壹個family,在保存到hdfs的時候store其實就是壹個目錄而已,真正存數據的是filestroe也就是hfile,每壹個hfile當達到壹定大小的時候就會拆分成兩個hfile所以壹個store目錄中會包含多個hfile。
因為table是按照rowkey來劃分region的,region默認的大小為256M,通常會設置得更高1G,2G,4G等,所以hfile不可能比region的的值要大。但是hfile有可能還是很大,在hdfs上會拆分成不同的block放在不同的datanode上,這樣子仍然無法做到精確定位。
hfile 繼續劃分,有data block,block index,trailler等組成,已經定位到rowkey所在的hfile時,會先讀取hfile的trailer的信息以獲取block index的位置,block index的key就是data block中的第壹個rowkey,所以通過block index 的key就能精確的定位到要檢索的rowkey在那個data block上,然後直接將該data block讀取到內存,需要註意的是這裏的data block已經很小了(默認是64k,不同於hdfs上的block默認為64M,hbase的hfile中的block要小的多)這樣子足以讀取該block到內存中,將該block進行遍歷就能獲取到需要的rowkey取出數據,以為這裏的block只有64k這樣的遍歷非常迅速。這就是為什麽hfile的data block要設置的如此之小的原因。