Hbase 讀取復(fù)雜原因:
主要基于兩個方面的原因:
- 一是因為HBase一次范圍查詢可能會涉及多個Region绿饵、多塊緩存甚至多個數(shù)據(jù)存儲文件(HFile);
- 二是因為HBase中更新操作以及刪除操作的實現(xiàn)都很簡單瓶颠。
插入&刪除: 沒有更新原始數(shù)據(jù)蝴罪,而是通過時間戳屬性新增版本。
刪除:只是插入deleted標簽步清。在Major Compact的時候刪除真正數(shù)據(jù)。
讀取過程需要根據(jù)版本進行過濾虏肾,對已經(jīng)標記刪除的數(shù)據(jù)也要進行過濾廓啊。
讀流程步驟:
- Client-Server讀取交互邏輯
- Server端Scan框架體系
- 過濾淘汰不符合查詢條件的HFile
- 從HFile中讀取待查找Key。
1. Client-Server讀取交互邏輯
Client首先會從ZooKeeper中獲取元數(shù)據(jù)hbase:meta表所在的RegionServer封豪,然后根據(jù)待讀寫rowkey發(fā)送請求到元數(shù)據(jù)所在RegionServer谴轮,獲取數(shù)據(jù)所在的目標RegionServer和Region(并將這部分元數(shù)據(jù)信息緩存到本地),最后將請求進行封裝發(fā)送到目標RegionServer進行處理吹埠。
hbase的讀取請求分為get和scan第步,而get實際是最簡單的一次scan疮装。
-
client-server端將scan沒有使用一次rpc,原因:
?大量數(shù)據(jù)傳輸會導(dǎo)致集群網(wǎng)絡(luò)帶寬等系統(tǒng)資源短時間被大量占用,嚴重影響集群中其他業(yè)務(wù)粘都。
?客戶端很可能因為內(nèi)存無法緩存這些數(shù)據(jù)而導(dǎo)致客戶端OOM廓推。
image.png 一次大的scan操作會拆分為多個RPC請求。每個RPC是一次next請求翩隧,分會規(guī)定數(shù)量的結(jié)果樊展。每次next()操作,客戶端先檢查本地緩存堆生,沒有就發(fā)一次RPC請求給服務(wù)器专缠,然后緩存到本地。
單次RPC caching大小默認是Integer.MAX_VALUE淑仆。設(shè)置過大可能因為一次獲取到的數(shù)據(jù)量太大導(dǎo)致服務(wù)器端/客戶端內(nèi)存OOM涝婉;設(shè)置太小會導(dǎo)致一次大scan進行太多次RPC,網(wǎng)絡(luò)成本高蔗怠。
對于一張表列過大墩弯,可以通過setBatch方法設(shè)置一次RPC請求的數(shù)據(jù)列數(shù)量。
客戶端還可以通過setMaxResultSize方法設(shè)置每次RPC請求返回的數(shù)據(jù)量大畜盎础(不是數(shù)據(jù)條數(shù))最住,默認是2G。
2 Server端Scan框架體系
一次scan可能會同時掃描一張表的多個Region怠惶≌歉浚客戶端會根據(jù)hbase:meta元數(shù)據(jù)將掃描的起始區(qū)間[startKey, stopKey)進行切分,切分成多個互相獨立的查詢子區(qū)間策治,每個子區(qū)間對應(yīng)一個Region脓魏。
HBase中每個Region都是一個獨立的存儲引擎,因此客戶端可以將每個子區(qū)間請求分別發(fā)送給對應(yīng)的Region進行處理通惫。下文會聚焦于單個Region處理scan請求的核心流程茂翔。
RegionServer接收到客戶端的get/scan請求之后做了兩件事情:首先構(gòu)建scanner iterator體系;然后執(zhí)行next函數(shù)獲取KeyValue履腋,并對其進行條件過濾珊燎。
-
構(gòu)建Scanner Iterator體系
1)過濾淘汰部分不滿足查詢條件的Scanner。
主要過濾策略有:TimeRange過濾遵湖、Rowkey Range過濾以及布隆過濾器
image.png
2)每個Scanner seek到startKey
-
根據(jù)HFile索引樹定位目標Block
image.png - BlockCache中檢索目標Block
Block緩存到Block Cache之后會構(gòu)建一個Map悔政,Map的Key是BlockKey,Value是Block在內(nèi)存中的地址延旧。其中BlockKey由兩部分構(gòu)成——HFile名稱以及Block在HFile中的偏移量谋国。BlockKey很顯然是全局唯一的。根據(jù)BlockKey可以獲取該Block在BlockCache中內(nèi)存位置迁沫,然后直接加載出該Block對象芦瘾。如果在BlockCache中沒有找到待查Block捌蚊,就需要在HDFS文件中查找。 -
HDFS文件中檢索目標Block
image.png
根據(jù)文件索引提供的Block Offset以及Block DataSize這兩個元素可以在HDFS上讀取到對應(yīng)的Data Block內(nèi)容近弟。
為什么HDFS的Block設(shè)計為128M缅糟,而HBase的Block設(shè)計為64K ?
1. HDFS Block 為128M藐吮,因為 主要存儲文件溺拱,Block太小,會導(dǎo)致Block元數(shù)據(jù)(Block所在DataNode位置谣辞、文件與Block之間的對應(yīng)關(guān)系等)龐大迫摔。因為HDFS元數(shù)據(jù)都存儲在NameNode上,大量的元數(shù)據(jù)很容易讓NameNode成為整個集群的瓶頸泥从。
2. HBase的緩存策略是緩存整個Block句占,如果Block設(shè)置太大會導(dǎo)致緩存很容易被耗盡,尤其對于很多隨機讀業(yè)務(wù)躯嫉,設(shè)置Block太大會讓緩存效率低下纱烘。
- 從Block中讀取待查找KeyValue
3)KeyValueScanner合并構(gòu)建最小堆
最小堆管理Scanner可以保證取出來的KeyValue都是最小的,這樣依次不斷地pop就可以由小到大獲取目標KeyValue集合祈餐,保證有序性擂啥。
執(zhí)行next函數(shù)獲取KeyValue并對其進行條件過濾
1)檢查該KeyValue的KeyType是否是Deleted/DeletedColumn/DeleteFamily等
2)檢查該KeyValue的Timestamp是否在用戶設(shè)定的Timestamp Range范圍
3)檢查該KeyValue是否滿足用戶設(shè)置的各種filter過濾器
4)檢查該KeyValue是否滿足用戶查詢中設(shè)定的版本數(shù)
總結(jié): 讀取過程中,是先根據(jù)TimeRange,Rowkey Range,bloomfilter判斷數(shù)據(jù)是否在對應(yīng)文件帆阳,再將文件中的數(shù)據(jù)讀取出來哺壶,判斷是否刪除,是否符合用戶條件蜒谤。
讀取過程總結(jié):
- 客戶端: 將scan 轉(zhuǎn)變?yōu)槎啻蝞ext請求山宾。將請求轉(zhuǎn)變?yōu)榘l(fā)送對應(yīng)region(讀zk,讀meta找到對應(yīng)region)的請求
- 服務(wù)器端:過濾掉不符合查詢條件的hfile鳍徽,讀取符合條件的hfile,構(gòu)建最小堆
(1)過濾hfile方式:TimeRange,RowKey,bloomfiler
(2) hfile索引樹定位目標block
(3)檢索block: blockcache中檢索资锰、hdfs文件中檢索block - 獲取keyvalue,next過濾:
(1)keytype判斷是否刪除
(2)timestamp判斷timerange
(3) 判斷用戶filter
(4) 判斷版本號