天天看點

hbase源碼系列(三)Client如何找到正确的Region Server

用戶端在進行put、delete、get等操作的時候,它都需要資料到底存在哪個region server上面,這個定位的操作是通過hconnection.locateregion方法來完成的。

這裡我們首先要講hbase的兩張中繼資料表-root-和.meta.表,它們一個儲存着region的分部資訊,一個儲存着region的詳細資訊。<b>在《hbase實戰》這本書裡面詳細寫了查找過程總共有8步:</b>

1)用戶端首先查詢zookeeper -root-表在哪裡

2)zookeeper告訴用戶端,-root-在regionserver rs1上面

3)用戶端向rs1發起查詢,哪一個.meta表可以查到t1表裡面的00009

4)rs1上的-root-告訴用戶端在rs3上面的.meta. region m2可以找到

5)用戶端向rs3上的.meta. region m2查詢t1表的00009行資料在哪個region上,哪一個region server可以提供服務

6)rs3告訴用戶端,在rs3上面的region t1r3

7)用戶端向rs3上面的region t1r3發起請求,我要讀取00009行

8)rs3上的region t1r3把資料發給用戶端,行,拿去吧

那在代碼裡面是怎麼體驗上述過程的呢?好,我們開始檢視locateregion這個方法,打開hconnectionmanager這個類。

tablename.meta_table_name,這個就是我們要找的-root-,在0.96裡面它已經被取消了,取而代之的是meta表中的第一個regionhregioninfo.first_meta_regioninfo,它位置在zk的meta-region-server節點當中的。

好吧,再回到代碼裡面,我們這裡肯定是走else這個路徑,我們進入locateregioninmeta看看。代碼好長啊,我們一點一點看吧,先從緩存裡面找,把tablename和rowkey傳進去。

這裡的cache是這樣組織的map&lt;tablename, softvaluesortedmap&lt;rowkey, hregionlocation&gt;&gt;, 通過tablename獲得它的基于rowkey的子map,這個map是按照key排好序的,如果找不到合适的key,就找比它稍微小一點的key。

接下來就是一個for循環了,預設是嘗試31次。

從上面的代碼分析,它在prefetchregioncache方法預先緩存了和表和row相關的位置資訊,核心的代碼如下:

這裡面的核心代碼隻有兩行,實作一個metascannervisitor,然後傳入到metascanner.metascan掃描一下,metascan會調用visiter的processrow方法,processrow方法把滿足條件的全都緩存起來。下面是條件,有興趣的人可以看一下,我折疊起來。

看一下metascanner.metascan吧,它也是用了new了一個htable。

然後根據有三種情況,<b>根據情況來建構scan的startkey:</b>

1.根據rowkey來掃描

2.全表掃

3.根據表的名來

這裡講一下根據rowkey來掃描吧,别的都很簡單,它用的是htable的getroworbefore來找到這個row,隻不過因為它是meta表,可以從zk上直接找到位置。

下面就開始scan了,這個scan的代碼,和我們平常用htable來掃描表是一樣的。

如果沒用緩存的情況,就隻能走接口的方式了,直接從伺服器去了,如果這都找不着,這一次就算結束了。

<b>好,現在最後總結一下吧:</b>

1)要查詢資料時候,在locateregion方法要先走locateregioninmeta這段

2)從zk當中擷取meta表的位置,通過這個位置資訊servername,獲得region server的接口,但是這裡先不用,留給不用緩存的情況用的

3)使用緩存的話,如果這個表沒被禁用,就先把要定位的整個表的region的位置資訊,全部緩存起來

4)在緩存表的過程當中,我們要借助new htable(tablename.meta_table_name, connection, null)來計算startkey和掃描。

5)把掃描到的表相關的位置資訊緩存起來,緩存之後取的過程這裡忘了交代了,通過表名找到表對應的一個hregioninfo,hregioninfo裡面包括startkey和stopkey,用rowkey一比對就知道是哪個region了。

6)不用緩存的情況,就走接口的方式,構造一個getrequest,調用region server裡面的get方法擷取到位置資訊。