1. 程式人生 > >轉:HBase之HFile詳解

轉:HBase之HFile詳解

HFile是HBase儲存資料的檔案組織形式。HFile經歷了三個版本,其中V2在0.92引入,V3在0.98引入。HFileV1版本的在實際使用過程中發現它佔用記憶體多,HFile V2版本針對此進行了優化,HFile V3版本基本和V2版本相同,只是在cell層面添加了Tag陣列的支援。

 

一 HFile 檔案結構

從以上圖片可以看出HFile主要分為四個部分:

Scanned Block Section: 順序掃描HFile,這個section的所有資料塊都被讀取,包括Leaf Index Block 和 Bloom Block

Non-Scanned Block Section: 順序掃描HFile,這個section的資料不會被讀取,主要包括元資料資料塊等

Load-On-Open-Section: 這部分資料在HRegionServer啟動時候,例項化HRegion並建立HStore的時候會將所有HFile的Load-On-Open-Section裡的資料載入進記憶體,主要存放了Root Data Index, Meta Index,FileInfo以及BloomFilter的元資料等

Trailer: 這部分主要記錄HFile的一些基本資訊,各個部分的偏移量和定址資訊

 

從物理角度看,如圖示:

 

 

二 HFileBlock

HFile會被切分為多個大小相等的block,每一個block大小可以在建立表列簇的時候通過blockSize引數指定,預設是64K,較大的blockSize有利於scan,較小的有利於隨即查詢(get)。

所有的block都有相同的資料結構,HBase將block塊抽象成HFile

Block。HFileBlock支援2種類型:一種型別不支援checksum,一種不支援。我們選用不支援checksum的HFileBlock解釋,下面是HFile

Block的內部結構:

 

 

從上圖可知,HFileBlock主要分為2個部分: Block Header 和 Block Dada. 其中Block Header 用來儲存元資料,包括block 型別,壓縮block大小,上一個block的偏移量等; 而Block Data主要儲存具體的資料。

Block Type: 主要用來記錄該Block的型別,HBase總共有8種Block

Type, 每一種block type對應的block都儲存不同的資料內容,有的儲存使用者資料,有的儲存索引資料,有的儲存meta元資料。對於任意一種型別的HFileBlock,都有著相同結構的Block Header,但是 Block Data結構可能去不相同,以下是簡單的Block Type介紹:

 

 

2.1 Trailer Block

主要記錄了HFile的基本資訊以及各個部分的偏移量等

 

 

HFile在讀取資料的時候,首先會解析Trailer Block,並載入到記憶體,然後再進一步載入Load-On-Open section的資料,具體步驟如下:

2.1.1 首先載入HFile版本資訊: HBase中version包含major version和minor version兩部分,前者決定了HFile的主版本v1,v2 or v3,後者決定了在主版本的基礎上是否支援一些微小的修正,比如是否支援checkum等。

 

2.1.2 根據HFile版本資訊,獲取trailer的長度,因為版本的trailer長度或許不一樣,然後再根據trailer長度載入整個HFile Trailer Block

 

2.1.3 載入Load-On-Open section到記憶體,起始偏移量是trailer中記錄的LoadOnOpenDataOffset,結束位置是HFile的length – trailer的length

 

2.2 Data Block

Data Block是HBase中資料儲存的最小單元,它儲存的是使用者KeyValue資料,資料結構如圖所示:

 

KeyValue: 是由四部分組成的

2.2.1 Key Length: 儲存key的長度,本身是4個位元組

2.2.2 Value Length: 儲存value的長度,本身是4個位元組

2.2.3 Key: 儲存資料的key,由Row Key Length+Row Key+Column Family Length +Column Family+Column Qualifier + TimeStamp+Key Type

2.2.3.1 Row Key Length: 儲存row key的長度,總共2位元組

2.2.3.2 Row : 儲存row的實際內容,其大小為row key length

2.2.3.3 Column Family Length:儲存列簇 Column Family的長度,佔1位元組

2.2.3.4 Column Family:儲存Column Family實際內容,大小為Column Family Length;

2.2.3.5 Column Qualifier:儲存Column Qualifier對應的資料,既然key中其他所有欄位的大小都知道了,整個key的大小也知道了,那麼這個Column Qualifier大小也是明確的了,無需再儲存其length

2.2.3.6 Time Stamp:儲存時間戳Time Stamp,佔8位元組

2.2.3.7 Key Type:儲存Key型別Key Type,佔1位元組,Type分為Put、Delete、DeleteColumn、DeleteFamilyVersion、DeleteFamily等型別,標記這個KeyValue的型別

 

KEY基礎設施大小(儲存各個部分長度的大小):

KEY_INFRASTRUCTURE_SIZE = ROW_LENGTH_SIZE + FAMILY_

LENGTH_SIZE + TIMESTAMP_SIZE + TYPE_SIZE;

也就是:儲存 row key的長度的大小 + 儲存 column family 的長度的大小 + 儲存timestamp長度的大小 + 儲存key type長度的大小 = 2 + 1 + 8 + 1 = 12位元組

 

KEY資料結構大小 = KEY_INFRASTRUCTURE_SIZE + ROW KEY LENGTH + COLUMN FAMILY LENGTH + COLUMNQUALIFIER LENGTH + TIMESTAMP LENGTH + KEY TYPE LENGTH

也就是:KEY基礎設施大小 + ROW KEY資料長度 + COLUMN FAMILY 資料長度 + COLUMN QUALIFEIR 資料長度 + 時間戳長度 + KEY TYPE資料長度

2.2.4 Value 儲存單元格CELL實際對應的值

 

2.3 BloomFilter Meta Block & Bloom Block

BloomFilter對於HBase隨機讀的效能至關重要,他可以避免讀取一些不會用到HFile,減少實際的IO次數,提高隨機讀的效能。

它的原理就是通過位陣列來實現過濾,初始狀態每一位都是0

 

 

然後BloomFilter對一個集合使用k個獨立的hash函式,分別將集合中的每一個元素進行對映到{1,m}的範圍。對於任何一個元素,然後根據對映的數字到位陣列確定位置,然後在該位置被置為1

 

下圖中集合S只有兩個元素x和y,分別被3個hash函式進行對映,對映到的位置分別為(0,2,6)和(4,7,10),對應的位會被置為1:

 

現在假如要判斷另一個元素是否是在此集合中,只需要被這3個hash函式進行對映,檢視對應的位置是否有0存在,如果有的話,表示此元素肯定不存在於這個集合,否則有可能存在。下圖所示就表示z肯定不在集合{x,y}中:

 

 

HBase中每個HFile都有對應的位陣列,KeyValue在寫入HFile時會先經過幾個hash函式的對映,對映後將對應的陣列位改為1,get請求進來之後再進行hash對映,如果在對應陣列位上存在0,說明該get請求查詢的資料不在該HFile中。

 

HFile中的位陣列就是Bloom Block儲存的值,可以想象,一個HFile檔案越大,裡面儲存的KeyValue就越多,位陣列也就會越大。一旦太大就不適合直接載入到記憶體,因此HFile V2在設計上將位陣列進行了拆分,拆分成多個獨立的陣列(根據key進行拆分,一部分連續的key使用一個位數組),這樣一個HFile就會包含多個位數組,根據key進行查詢,首先會定位到具體的某一個位數組,只需要載入此位陣列到記憶體即可

 

在結構上,每一個位數組對應HFile一個Bloom Block,為了方便根據key定位具體需要載入哪個位陣列,HFile V2又設計了對應的索引

Bloom Index Block,對應的記憶體和邏輯結構如下:

 

 

2.3.1 TotalByteSize: 表示位陣列大小

2.3.2 NumChunks: 表示Bloom Block個數

2.3.3 HashCount: 表示hash函式個數、

2.3.4 HashType: 表示hash函式型別

2.3.5 TotalKeyCount: 表示Bloom Filter已經包含的key資料

2.3.6 TotalMaxKeys: 表示Bloom Filter 當前包含最多的key的數目

 

Bloom Index Entry:

BlockOffset: 表示對應的Bloom Block在HFile中偏移量

FirstKey: 表示BloomBlock中第一個Key

根據上文所說,一次get請求進來,首先會根據key在所有的索引條目中進行二分查詢,查詢到對應的Bloom Index Entry,就可以定位到該key對應的位陣列,載入到記憶體進行過濾判斷。