本文目錄如下所示:
目錄
- HFile在HBase架構中的位置
- 什么是HFile
- HFile邏輯結構
- HFile邏輯結構的優點
- HFile物理結構
- HFile生成流程
- HFile中Block塊解析
- 多大的HFile文件才存在Intermiate Index Block
HFile在HBase架構中的位置

如上圖所示,HFile是HBase最底層的文件組織形式。
Table
--N Region
--N Store
--N StoreFile
--HFile(StoreFile與HFile是一對一)
什么是HFile
HFile是HBase存儲數據的文件組織形式,參考BigTable的SSTable和Hadoop的TFile實現。
從HBase開始到現在,HFile經歷了三個版本,其中V2在0.92引入,V3在0.98引入。HFileV1版本的在實際使用過程中發現它占用內存多,HFile V2版本針對此進行了優化,HFileV3版本基本和V2版本相同,只是在cell層面添加了Tag數組的支持。鑒於此,本文主要針對V2版本進行分析。
HFile邏輯結構
最初的HFile格式(HFile V1)

Data Block默認大小為64k。
Data Index部分存儲了每一個Data Block的索引信息{Offset,Size,FirstKey},這里只有1級索引,當HFile較大,索引信息過多,導致一個RegionServer啟動時可能需要加載數GB的Data Block Index數據。這在一個大數據量的集群中,幾乎無法忍受。另外,第一次讀取時需要加載所有的Bloom Filter數據到內存中。一個HFile中的Bloom Filter的數據大小可達百MB級別。
Data Block Index究竟有多大?
一個Data Block在Data Block Index中的索引信息包含{Offset, Size, FirstKey},BlockOffset使用Long型數字表示,Size使用Int表示即可。假設用戶數據RowKey的長度為50bytes,那么,一個64KB的Data Block在Data Block Index中的一條索引數據大小約為62字節。
假設一個RegionServer中有500個Region,每一個Region的數量為10GB(假設這是Data Blocks的總大小),在這個RegionServer上,約有81920000個Data Blocks,此時,Data Block Index所占用的大小為81920000*62bytes,約為4.7GB
HFile V2設計
作為V1的改進版,V2解決了此前存在的問題。

文件主要分為四個部分:Scanned block section,Non-scanned block section,Opening-time data section和Trailer。
Scanned block section:顧名思義,表示順序掃描HFile時所有的數據塊將會被讀取,包括Leaf Index Block和Bloom Block。
Non-scanned block section:表示在HFile順序掃描的時候數據不會被讀取,主要包括Meta Block和Intermediate Level Data Index Blocks兩部分。
Load-on-open-section:這部分數據在HBase的region server啟動時,需要加載到內存中。包括FileInfo、Bloom filter block、data block index和meta block index。
Trailer:這部分主要記錄了HFile的基本信息、各個部分的偏移值和尋址信息。
HFile邏輯結構的優點
- 分層索引
Data Block的索引,在HFile V2中最多可支持三層索引:
- Root Data Index
- Intermediate Index Block
- Leaf Index Block
- Data Block
- Leaf Index Block
- Intermediate Index 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階段或讀取階段一次讀入大量的數據,有效降低時延。
將索引分級后,RegionServer不需要將所有索引都加載,加載一級索引即可。
HFile物理結構
-
所有block塊都擁有相同的數據結構,如圖左側所示,HBase將block塊抽象為一個統一的HFileBlock。HFileBlock支持兩種類型,一種類型不支持checksum,一種不支持。

-
不支持checksum的HFileBlock內部結構:

HFileBlock主要包括兩部分:BlockHeader和BlockData。其中BlockHeader主要存儲block元數據,BlockData用來存儲具體數據。
block元數據中最核心的字段是BlockType字段,用來標示該block塊的類型,HBase中定義了8種BlockType,每種BlockType對應的block都存儲不同的數據內容,有的存儲用戶數據,有的存儲索引數據,有的存儲meta元數據。對於任意一種類型的HFileBlock,都擁有相同結構的BlockHeader,但是BlockData結構卻不相同。
- 每種BlockType進行詳細的講解:

HFile中Block塊解析


HFile生成流程
基本思路:先填滿內容,再生成header,最后生成checksum之類。
起初,HFile中並沒有任何Block,數據還存在於MemStore中。
Flush發生時,創建HFile Writer,第一個空的Data Block出現,初始化后的Data Block中為Header部分預留了空間,Header部分用來存放一個Data Block的元數據信息。
而后,位於MemStore中的KeyValues被一個個append到位於內存中的第一個Data Block中:


- Header內容


為輸出的Data Block生成一條索引記錄,包含這個Data Block的{起始Key,偏移,大小}信息,這條索引記錄被暫時記錄到內存的Block Index Chunk中:

Leaf Index Block:





- Bloom Filter

多大的HFile文件才存在Intermiate Index Block
基於每一個Block中的FirstKey為50bytes的假設,一個128KB的Root Index Block可容納的HFile文件總大小約為252GB。
如果實際的RowKey小於50 Bytes,或者將Data Block的Size調大,一個128KB的Root Index Chunk所關聯的HFile文件將會更大。因此,在大多數場景中,Intermediate Index Block並不會存在。
總結
關於架構設計的一些基本思想在HFile中得到充分體現,分治(HFile本身屬於分治的產物,Table的存儲被分解成HFile的存儲)、HFileBlock的抽象,分層(索引),架構演進(v1/v2/v3的演進)。
另外HFileBlock數據結構設計比較好,支持8種結構。
