master啟動的時候會初始化masterquotamanager,並啟動該manager;
masterquotamanager實現了regionstatelistener介面,可以監聽region的狀態變化,regionstatelistener介面中定義了三個事件,分別是onregionsplit,onregionsplitreverted,onregionmerged。
masterquotamanager中包括了三把鎖,分別是namespacelocks、tablelocks和userlocks。
masterquotamanager中包括乙個namespacequotamanger,namespacequotamanger用於在namespace下的table以及table region發生變化時,能夠保持住namespace的quota不變。
使用者的setquota請求是路由到master上去執行的。
masterquotamanager負責quota表的建立管理,並根據使用者命令在quota表中新增、修改或者刪除資料,主要的方法就是setquota(final setquotarequest req),方法中由於使用namedlock,因此對同一namespace、table和user,同一時刻只有乙個修改可被執行。
quota是被快取在cache(乙個concurrenthashmap的資料結構)中的,分別是namespacequotacache、tablequotacache和userquotacache,由quotacache類管理,這個類的成員變數quotarefresherchore繼承了scheduledchore,會定期排程,預設的排程週期是5分鐘(refresh_default_period),此外還有個淘汰因子(evict_period_factor,預設是5)。
quotacache只要用於快取在regionserver中,regionserverquotamanager每從cache中取出一條資料,該條資料的lastquery就會更新為當時的取出時間,如果一條資料長期沒有被query,當時間超過了evictperiod(淘汰因子*排程週期,25分鐘),那麼這條資料就會被置換出記憶體。
cache中的每條記錄都記錄了lastupdate,這個欄位的值是該記錄從quota table中讀出時的當時時間,如果一條的lastupdate超過了refreshperiod(5分鐘),那麼這條快取會失效並從table重新讀取更新;
regionserver啟動之後會新建立regionserverquotamanager並啟動它,regionserverquotamanager的主要作用就是維護了乙份quota快取(也就是上面說到的quotacache),並定期更新快取中的值,regionserver對外提供了getquota和checkquota兩個方法,其中:
rsrpcservices中的get/mutate/scan三個方法執行前會呼叫regionserverquotamanager的checkquota,checkquota從使用者請求中解析出使用者名稱,使用者組,使用者請求的table等資訊,首先根據這些資訊去獲取當前可用的配額資訊(getquota方法)。
這塊有個非常複雜的設計,我們前面講過,配額是快取在quotacahe的三個map中,這些map的value是quotastate型別的物件,當快取更新也就是呼叫相應的fetch***quotastate方法時,會從table中逐一讀出使用者設定的quota值,並對每一條讀出的結果通過setquotas,注入到quotastate的globallimiter中,返回的globallimiter是timebasedlimiter(實現了quotalimiter介面)型別的物件。
timebasedlimiter這個物件中管理了所有的限額資料,包括reqslimiter/reqsizelimiter/writesizelimiter/writesizelimiter/readreqslimiter/readsizelimiter。
再說回到checkquota,checkquota拿到了限額資訊就是前面說到globallimiter,也就是quotalimiter型別的物件。
使用者a訪問namespace b下的table c,這種場景下,getquota方法會同時拿到a、b、c三者的quotalimiter,將三者包裝成乙個defaultoperationquota返回,然後呼叫defaultoperationquota的checkquota以檢查請求是否超過了限額。checkquota的方法主體如下圖:
方法會將使用者請求折算成writesize或者readsize,然後與已有配額作對比(也就是canexecute方法的內容),如果write&readsize超過了配額大小,那麼canexecute會返回false。那麼此時服務端會丟擲throttlingexception異常,這個異常會一直向上拋回給客戶端。
注意限額是會定期refill的,refill的邏輯在ratelimiter的refill方法中,此方法的意義如下面這段注釋中所說:
* this limiter will refill resources at every timeunit/resources interval. for example: for a
* limiter configured with 10resources/second, then 1 resource will be refilled after every 100ms
* (1sec/10resources)
如果請求的size小於限額,那麼canexecute返回true,並呼叫limiter的grabquota方法更新各個limiter已消耗的配額。checkquota方法返回,使用者請求繼續執行,注意的checkquota方法在使用者請求路徑上的第一步,也就是服務端ipc收到使用者請求後首先檢查配額是否滿足,如果不滿,就拋異常拒絕掉請求,此時請求未對服務端的記憶體,磁碟io,網路io等造成消耗。
總結起來,hbase服務端的限流設計大體上如下圖中所示:
主要要點有以下幾點:
1、請求限額既可以限制單位時間的請求數,也可以限制請求量,如讀次數/s,可讀mb/s等等;
2、服務端接收到使用者請求後第一步就是檢視配額是否足夠,如果充足,請求繼續執行,否則拋回給客戶端throttlingexception異常;
3、每接收乙個請求,配額會做相應的扣減,同時配額會定期refill,refill邏輯取了配額的倒數,既10次/s的配額,那麼每100ms會恢復乙個配額;
4、regionserverquotamanager的快取更新邏輯包含兩層,quotacache中的資料每5分鐘更新一次,每25分鐘將quotacache這段時間內未touch的資料刪除掉;
hbase自帶的限流規則對請求型別的區分比較粗,只區分了read&write,對read中進一步的scan&get則未區別對待,在實際使用中,我們發現scan請求由於服務端處理時間較長,因此占用handler的時間也就長,導致其他請求因為獲取不到handler而被阻塞。而大量的put可能造成的後果是memstore頻繁地被寫滿,導致regionserver的flush頻繁發生,這一方面增多了因flush導致的記憶體碎片,另一方面在hdfs中積累了大量的小檔案,既增大了regionserver管理這些hfile檔案的記憶體壓力,也增大了發生major compact的可能。
因此使用建議如下:
HiveHA機制原始碼分析
hive讓大資料飛了起來,不再需要專人寫mr。平常我們都可以用基於thrift的任意語言來呼叫hive。不過愛恨各半,hive的thrift不穩定也是出了名的。很容易就出問題,讓人無計可施。唯一的辦法就是不斷kill,不斷restart。當然,我們可以用haproxy來解決這個問題,關鍵,hapro...
思科VPP原始碼分析(dpo機制原始碼分析)
vpp的dpo機制跟路由緊密結合在一起。路由表查詢 ip4 lookup 的最後結果是乙個load balance t結構。該結構可以看做是乙個hash表,裡面包含了很多dpo,指向為下一步處理動作。每個dpo都是新增路由時的乙個path的結果。dpo標準型別有 dpo drop,dpo ip nu...
JDK類載入機制原始碼分析及原始碼分析
jvm的類載入機制主要有如下三種機制 1.全盤負責 所謂全盤負責,就是說當乙個類載入器載入個個class的時候,該class所依賴和引用的其他class也將由該類載入 器負責載入,除非使用另外乙個類載入器來載入。2.雙親委託 所謂雙親委託則是先讓parent 父 類載入器試圖載入該class 若父載...