天天看點

HBase get源碼解析

用戶端

獲得RPC連結 遞歸查找對應rowkey的位址 遞歸:table - .METE. - ROOT

HConnectionManager - locateRegionInMeta
在metatable中查找region位址:
                metaLocation = locateRegion(parentTable,metaKey);
           

發送查詢請求到用戶端

服務端

一、執行個體化HRegion

獲得Get請求,HRegionServer

public Result get(byte[] regionName,Get get){
HRegion region = getRegion(regionName);//1
return region.get(get,getLockFromId(get.getLockId()));//2
}
           

二、HRegion調用Get方法 

1.通過name獲得HRegion

 2.HRegion運作get方法,檢查rowkey,cf;

public Result get(final Get get,final Integer locakid)
           

 調用HRegion内部方法get

private List<KeyValue> get(Get get,boolean withCoprocessor)
           

三、執行個體化Scan,和Region疊代器RegionScanner,疊代查詢Region資料

get方法中執行個體化Scan,執行個體化疊代Region的RegionScanner

             --HRegion調用instantialRegionScanner

                執行個體化内部類RegionScannerImpl

             --疊代cf,每個cf生成一個Store和負責疊代資料的StoreScanner

StoreScanner scanner = store.getScanner(scan,entry.getValue());

private List<KeyValueScanner> getScanners(Scan scan,final NavigableSet<byte[]> columns)
           

四、執行個體化StoreScanner,疊代每個cf的資料

 StoreScanner的内部變量keyValueHead,是keyValueSanner的集合

protected List<KeyValueScanner> getScanners(boolean cacheBlocks,boolean isGet,boolean isCompaction)
           

 此方法會執行個體化兩種Scanner

  StoreScanner構造方法,獲得兩部分scanner

List<KeyValueScanner> scanners = getScannersNoCompaction();
           

   1.記憶體Scanner,負責疊代在記憶體中(LSM資料結構,未寫到HFile中的資料)

memStoreScanners = this.memestore.getScanners()
           

   2.HFile的Scanner,負責疊代HFile,會執行個體化多個StoreFileScanner

storeFiles = this.getStorefiles()
List<StoreFileScanner> sfScanners = StoreFileScanner.getScannersForStoreFiles(storeFiles,cacheBlocks,isGet,isCompaction)
           

  傳回所有keyValueScanner(記憶體的、檔案的)

五、獲得KeyValue結果

   RegionScannerImpl調用Next方法

public synchronized boolean next(List<KeyValue> outResults,int limit)
boolean returnResult = nextInternal(limit)
           

 在此方法中,生成keyvalue資料結果,通過RPC傳回給用戶端,查詢就結束了

小結:

   從分析可見,hbase的get也是一次scan請求,因為Hbase的LSMTree結果,最小機關也隻是HFile(hbase布隆過濾器可以有助判斷rowkey不是在某個HFile中)。

  對比scan,get知道确切一個Region,limit為1;是以在region配置設定合理下,get速度可以到毫秒級。這裡也就建議scan時,要有startrowkey,endrowkey,減少便利region數

輔助:

4 布隆過濾器(Bloom filters)
資料塊索引提供了一個有效的方法,在通路一個特定的行時用來查找應該讀取的HFile的資料塊。但是它的效用是有限的。HFile資料塊的預設大小是64KB,這個大小不能調整太多。
如果你要查找一個短行,隻在整個資料塊的起始行鍵上建立索引無法給你細粒度的索引資訊。例如,如果你的行占用100位元組存儲空間,一個64KB的資料塊包含(64 * 1024)/100 = 655.53 = ~700行,而你隻能把起始行放在索引位上。你要查找的行可能落在特定資料塊上的行區間裡,但也不是肯定存放在那個資料塊上。這有多種情況的可能,或者該行在表裡不存在,或者存放在另一個HFile裡,甚至在MemStore裡。這些情況下,從硬碟讀取資料塊會帶來IO開銷,也會濫用資料塊緩存。這會影響性能,尤其是當你面對一個巨大的資料集并且有很多并發讀使用者時。
布隆過濾器允許你對存儲在每個資料塊的資料做一個反向測試。當某行被請求時,先檢查布隆過濾器看看該行是否不在這個資料塊。布隆過濾器要麼确定回答該行不在,要麼回答它不知道。這就是為什麼我們稱它是反向測試。布隆過濾器也可以應用到行裡的單元上。當通路某列辨別符時先使用同樣的反向測試。
布隆過濾器也不是沒有代價。存儲這個額外的索引層次占用額外的空間。布隆過濾器随着它們的索引對象資料增長而增長,是以行級布隆過濾器比列辨別符級布隆過濾器占用空間要少。當空間不是問題時,它們可以幫助你榨幹系統的性能潛力。
你可以在列族上打開布隆過濾器,如下所示:
hbase(main):007:0> create 'mytable',
{NAME => 'colfam1', BLOOMFILTER => 'ROWCOL'}
BLOOMFILTER參數的預設值是NONE。一個行級布隆過濾器用ROW打開,列辨別符級布隆過濾器用ROWCOL打開。行級布隆過濾器在資料塊裡檢查特定行鍵是否不存在,列辨別符級布隆過濾器檢查行和列辨別符聯合體是否不存在。ROWCOL布隆過濾器的開銷高于ROW布隆過濾器。
           

繼續閱讀