本文由 網易雲 發佈。數組
做者:範欣欣數據結構
本篇文章僅限內部分享,如需轉載,請聯繫網易獲取受權。函數
HFile是HBase存儲數據的文件組織形式,參考BigTable的SSTable和Hadoop的TFile實現。從HBase開始到如今,HFile經歷了三個版本,其中V2在0.92引入,V3在0.98引入。HFileV1版本的在實際使用過程當中發現它佔用內存多,HFile V2版本針對此進行了優化,HFile V3版本基本和V2版本相同,只是在cell層面添加了Tag數組的支持。鑑於此,本文主要針對V2版本進行分析,對V1和V3 版本感興趣的同窗能夠參考其餘信息。oop
HFile V2的邏輯結構以下圖所示:性能
文件主要分爲四個部分:Scanned block section,Non-scanned block section,Load-on-open-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。spa
Trailer:這部分主要記錄了HFile的基本信息、各個部分的偏移值和尋址信息。設計
如上圖所示,HFlie會被切分爲多個大小相等的block塊,每一個block的大小能夠在建立表列簇的時候經過參數blocksize=>’65535‘進行指定,默認爲64K,大號的Block有利於順序Scan,小號Block利於隨機查詢,於是須要權衡。並且全部block塊都擁有相同的數據結構,如圖左側所示,HBase將block塊抽象爲一個統一的HFileBlock。HFileBlock支持兩種類型,一種類型不支持checksum,一種不支持。爲方便講解,下圖選用不支持checksum的HFileBlock內部結構:3d
上圖所示HFileBlock主要包括兩部分:BlockHeader和BlockData。其中BlockHeader主要存儲block元數據,BlockData用來存儲具體數據。block元數據中最核心的字段是BlockType字段,用來標示該block塊的類型,HBase中定義了8種BlockType,每種BlockType對應的block都存儲不一樣的數據內容,有的存儲用戶數據,有的存儲索引數據,有的存儲meta元數據。對於任意一種類型的HFileBlock, 都擁有相同結構的BlockHeader , 可是BlockData結構卻不相同。下面經過一張表簡單羅列最核心的幾種BlockType,下文會詳細針對每種BlockType進行詳細的講解:
上文從HFile的層面將文件切分紅了多種類型的block,接下來針對幾種重要block進行詳細的介紹,由於篇幅的緣由,索引相關的block不會在本文進行介紹,接下來會寫一篇單獨的文章對其進行分析和講解。首先會介紹記錄HFile基本信息的TrailerBlock,再介紹用戶數據的實際存儲塊DataBlock,最後簡單介紹布隆過濾器相關的block。
Trailer Block
TrailerBlock主要記錄了HFile的基本信息、各個部分的偏移值和尋址信息,下圖爲Trailer內存和磁盤中的數據結構,其中只顯示了部分核心字段:
HFile在讀取的時候首先會解析Trailer Block並加載到內存,而後再進一步加載LoadOnOpen區的數據,具體步驟以下:
1. 首先加載version版本信息,HBase中version包含majorVersion和minorVersion兩部分,前者決定了HFile的主版本:V一、V2 仍是V3;後者在主版本肯定的基礎上決定是否支持一些微小修正,好比是否支持checksum等。不一樣的版本決定了使用不一樣的Reader對象對HFile進行讀取解析
2. 根據Version信息獲取trailer的長度(不一樣version的trailer長度不一樣),再根據trailer長度加載整個HFileTrailer Block
3.最後加載load-on-open部分到內存中,起始偏移地址是trailer中的LoadOnOpenDataOffset字段,load-on-open部分的結束偏移量爲HFile長度減去Trailer長度,load-on-open部分主要包括索引樹的根節點以及Filelnfo兩個重要模塊,Filelnfo是固定長度的 塊 ,它紀錄了文的一些Meta信息,例 如 : AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等;索引樹根節點放到下一篇文章進行介紹。
Data Block
DataBlock 是HBase 中數據存儲的最小單元。DataBlock 中主要存儲用戶的KeyValue 數據( KeyValue 後面通常會跟一個timestamp , 圖中未標出), 而KeyValue結構是HBase存儲的核心, 每一個數據都是以KeyValue結構在HBase中進行存儲。KeyValue結構在內存和磁盤中能夠表示爲:
每一個KeyValue都由4個部分構成,分別爲key length,value length,key和value。其中key value和value length是兩個固定長度的數值,而key是一個複雜的結構,首先是rowkey的長度,接着是rowkey,而後是ColumnFamily的長度,再是ColumnFamily, 最後是時間戳和KeyType(keytype有四種類型,分別是Put、Delete、 DeleteColumn和DeleteFamily),value就沒有那麼複雜,就是一串純粹的二進制數據。
BloomFilter Meta Block & Bloom Block
BloomFilter對於HBase的隨機讀性能相當重要,對於get操做以及部分scan操做能夠剔除掉不會用到的HFile文件,減小實際IO次數,提升隨機讀性能。在此簡單地介紹一下Bloom Filter的工做原理,Bloom Filter使用位數組來實現過濾,初始狀態下位數組每一位都爲0,以下圖所示:
假如此時有一個集合S = {x1, x2, … xn},Bloom Filter使用k個獨立的hash函數,分別將集合中的每個元素映射到{1,…,m}的範圍。對於任何一個元素,被映射到的數字做爲對應的位數組的索引,該位會被置爲1。好比元素x1被hash函數映射到數字8,那麼位數組的第8位就會被置爲1。下圖中集合S只有兩個元素x和y,分別被3個hash函數進行映射,映射到的位置分別爲(0,3,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,對應的內存和邏輯結構圖以下:
Bloom Index Block結構中totalByteSize表示位數組的bit數,numChunks表示Bloom Block的個數,hashCount表示hash函數的個數,hashType表示hash函數的類型,totalKeyCount表示bloom filter當前已經包含的key的數目,totalMaxKeys表示bloomfilter當前最多包含的key的數目, Bloom Index Entry對應每個bloom filter block的索引條目,做爲索引分別指向’scanned block section’部分的Bloom Block,Bloom Block中就存儲了對應的位數組。
Bloom Index Entry 的結構見上圖左邊所示, BlockOffset 表示對應Bloom Block 在HFile 中的偏移量, FirstKey 表示對應BloomBlock的第一個Key。根據上文所說,一次get請求進來,首先會根據key在全部的索引條目中進行二分查找,查找到對應的Bloom Index Entry,就能夠定位到該key對應的位數組,加載到內存進行過濾判斷。
這篇小文首先從宏觀的層面對HFile的邏輯結構和物理存儲結構進行了講解,而且將HFile從邏輯上分解爲各類類型的Block,再接着從微觀的視角分別對Trailer Block、Data Block在結構上進行了解析:經過對Trailer Block的解析,能夠獲取HFile的版本以及HFile中其餘幾個部分的偏移量,在讀取的時候能夠直接經過偏移量對其進行加載;而對Data Block的解析能夠知道用戶數據在HDFS中是如何實際存儲的;最後經過介紹Bloom Filter的工做原理以及相關的Block塊瞭解HFile中Bloom Filter的存儲結構。接下來會以本文爲基礎,再寫一篇文章分析HFile中索引塊的結構以及相應的索引機制。
網易有數:企業級大數據可視化分析平臺。面向業務人員的自助式敏捷分析平臺,採用PPT模式的報告製做,更加易學易用,具有強大的探索分析功能,真正幫助用戶洞察數據發現價值。可點擊這裏免費試用。
瞭解 網易雲 :
網易雲官網:https://www.163yun.com/
新用戶大禮包:https://www.163yun.com/gift
網易雲社區:https://sq.163yun.com/