【每日五分鐘搞定大數據】系列,HBase第四篇算法
這一篇你能夠知道,apache
HFile的內部結構?緩存
HBase讀文件細粒度的過程?分佈式
HBase隨機讀寫快除了MemStore以外的緣由?oop
上一篇中提到了Hbase的數據以HFile的形式存在HDFS, 物理存儲路徑是:大數據
NameSpace->Table->Region->CF->HFile
這一篇咱們來講下這個HFile,把路徑從HFile開始再補充一下優化
HFile->Block->KeyValue.
順便科普一下,HFile具體存儲路徑爲:code
/hbase/data/<nameSpace>/<tableName>/<encoded-regionname>/<column-family>/<filename>
如何讀取HFile的內容:blog
hbase org.apache.hadoop.hbase.io.hfile.HFile -f /上面的路徑指定某個HFile -p
這是我作的一個思惟導圖,這裏面的內容就是我這章要講的東西,有點多,你們慢慢消化。
索引
Scanned block section:掃描HFile時這個部分裏面的全部block都會被讀取到。
Non-scanned block section:和相面的相反,掃描HFile時不會被讀取到。
Load-on-open-section:regionServer啓動時就會加載這個部分的數據,不過不是最早加載。
Trailer:這個部分纔是最早加載到內存的,記錄了各類偏移量和版本信息。
物理分類和邏輯分類對應的關係,能夠在上面的圖中看到
HFile有多個大小相等的block組成,Block分爲四種類型:Data Block,Index Block,Bloom Block和Meta Block。
保存了實際的數據,由多個KeyValue 組成,塊大小默認爲64K(由建表時建立cf時指定或者HColumnDescriptor.setBlockSize(size)),在查詢數據時,以block爲單位加載數據到內存。
KeyValue 的結構
這三層索引我舉個栗子放在一塊兒說,第一層是必需要的,也是最快的,由於它會被加載到內存中。二三根據數據量決定,若是有的話在找的時候也會加載到內存。實際上就是一步步的縮小範圍,相似B+樹的結構:
a,b,c,d,e f,g,h,i,j k,l,m,n,o Root Index Block 第一層:a,g,l Intermediate Level Data Index Block 第二層:a,c,e || f,h,j || k ,m,o Leaf Index Block 第三層(部分):a,b || c,d || e,f
上面的流程一共IO了三次,HBase提供了一個BlockCache,是用在第4步緩存數據塊,能夠有必定機率免去隨後一次IO。
相關配置:
hfile.data.block.size(默認64K):一樣的數據量,數據塊越小,數據塊越多,索引塊相應的也就越多,索引層級就越深
hfile.index.block.max.size(默認128K):控制索引塊的大小,索引塊越小,須要的索引塊越多,索引的層級越深
保存用戶自定義的kv對,能夠被壓縮。好比booleam filter就是存在元數據塊中的,該塊只保留value值,key值保存在元數據索引塊中。每個元數據塊由塊頭和value值組成。能夠快速判斷key是都在這個HFile中。
Meta Block的索引。
不被壓縮,用戶也能夠在這一部分添加本身的元信息。
記錄了HFile的基本信息、偏移值和尋址信息
Trailer Block
另外:Bloom filter相關的Block我準備專門寫一篇文章,由於Bloom filter這個東西在分佈式系統中很是常見並且有用,如今須要知道的是它是用來快速判斷你須要查找的rowKey是否存在於HFile中(一堆的rowKey中)。
看完上面的內容咱們就能夠解決文章開始提出的問題了:
HBase讀文件細粒度的過程?
HBase隨機讀寫快除了MemStore以外的緣由?
這兩個問題我一塊兒回答。
0.這裏從找到對應的Region開始提及,前面的過程能夠看上一篇文章。
1.首先用MemStoreScanner搜索MemStore裏是否有所查的rowKey(這一步在內存中,很快),
2.同時也會用Bloom Block經過必定算法過濾掉大部分必定不包含所查rowKey的HFile,
3.上面提到在RegionServer啓動的時候就會把Trailer,和Load-on-open-section裏的block前後加載到內存,
因此接下來會查Trailer,由於它記錄了每一個HFile的偏移量,能夠快速排除掉剩下的部分HFile。
4.通過上面兩步,剩下的就是不多一部分的HFile了,就須要根據Index Block索引數據(這部分的Block已經在內存)快速查找rowkey所在的block的位置;
5.找到block的位置後,檢查這個block是否在blockCache中,在則直接去取,若是不在的話把這個block加載到blockCache進行緩存,
當下一次再定位到這個Block的時候就不須要再進行一次IO將整個block讀取到內存中。
6.最後掃描這些讀到內存中的Block(可能有多個,由於有多版本),找到對應rowKey返回須要的版本。
另外,關於blockCache不少人都理解錯了,這裏要注意的是:
blockCache並無省去掃描定位block這一步,只是省去了最後將Block加載到內存的這一步而已。
這裏又引出一個問題,若是BlockCache中有須要查找的rowKey,可是版本不是最新的,那會不會讀到髒數據?
HBase是多版本共存的,有多個版本的rowKey那說明這個rowKey會存在多個Block中,其中一個已經在BlockCache中,則省去了一次IO,可是其餘Block的IO是沒法省去的,它們也須要加載到BlockCache,而後多版本合併,得到須要的版本返回。解決多版本的問題,也是rowKey須要先定位Block而後纔去讀BlockCache的緣由。