1. 背景
在了解HBCK2之前,建議先了解一下啥是HBCK。HBCK是HBase1.x中的命令,到了HBase2.x中,HBCK命令不適用,且它的寫功能(-fix)已刪除,它雖然還可以報告HBase2.x集群的狀態(tài),但是由于它不了解HBase2.x集群內(nèi)部的工作原理,因此其評估將不準(zhǔn)確。因此,如果你正在使用HBase2.x,那么對HBCK2應(yīng)該需要了解一些,即使你不經(jīng)常用到。
2. 獲取HBCK2
HBCK2已經(jīng)被剝離出HBase成為了一個單獨的項目,如果你想要使用這個工具,需要根據(jù)自己HBase的版本,編譯源碼。其GitHub地址為:https://github.com/apache/hbase-operator-tools.git
默認(rèn)HBase的版本是2.1.6,可以在父pom.xml文件里修改成你需要的版本,我們線上集群的版本是cdh-6.3.1-hbase2.1.0,與默認(rèn)版本接近,因此我就使用默認(rèn)的版本。
項目根目錄下運(yùn)行打包命令:
mvn clean install -DskipTests
編譯成功后的截圖:

Base-hbck2的target目錄下可以找到我們最后需要的jar

把該jar包上傳到集群隨便一個目錄下。
3. 測試命令是否可以正常使用
開始使用HBCK2的命令,最直接的使用方式:
./bin/hbase hbck -j <jar包地址> <命令>
使用HBCK2禁用啟用測試表。
運(yùn)行禁用表命令:
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar setTableState leo_test DISABLED
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar 指定jar包的方式使用HBCK2命令
setTableState 改變表狀態(tài)的命令
leo_test 表名
DISABLED 禁用狀態(tài)
看圖,表的狀態(tài)已經(jīng)被更改為DISABLED

運(yùn)行啟用表命令:
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar setTableState leo_test ENABLED
看圖,表的狀態(tài)已經(jīng)被更改為ENABLED

有個疑問就是,表狀態(tài)被更改為DISABLED,這張表的region依然是online狀態(tài),表依然可以被正常查詢。
以上操作順利執(zhí)行,就可以證明我們的HBCK2命令被安裝成功了。
4. Procedure簡介
HBase2集群幾乎所有的操作都是通過procedure進(jìn)行的,因此,HBCK2的工作實際就是修復(fù)各種不正常的procedure。
一個procedure是由一系列的操作組成,一旦完成,要么成功,要么失?。≧OLL BACK),不存在中間狀態(tài),所以,procedure是支持事物的。
procedure執(zhí)行的每一步都會以log的形式持久化在HBase的MasterProcWals目錄下,這樣master重啟時也能通過日志來恢復(fù)之前的狀態(tài)且繼續(xù)執(zhí)行。
對于運(yùn)維而言最重要的一點就是procedure在執(zhí)行過程中會拿好幾把鎖, 這個在處理問題時是很重要的,因為一旦鎖沒有釋放,再做任何操作也只能是卡住等鎖。
IdLock:procedure級別的鎖,保證一個procedure不會被多個線程同時執(zhí)行。
資源鎖:對HBase的內(nèi)部資源進(jìn)行加鎖,不同的procedure加鎖的粒度不同,目前有region/table/namespace/region server級別的鎖。
舉例來說,假設(shè)我assign一個region,那么procedure在執(zhí)行的時候就需要對這個region進(jìn)行加鎖,這樣如果有別的人想要unassign這個region,或者drop這個region所在的table,都需要等最早的assignment結(jié)束后釋放鎖了才能執(zhí)行。這樣防止有不一致的情況出現(xiàn)。
5. HBCK2核心功能介紹
5.1 bypass [OPTIONS] <PID> ...
bypass可以將一個或多個卡住的procedure進(jìn)行釋放。
原理是,在procedure的類里有一個bypass的flag,每次執(zhí)行時會檢查這個flag是否為true,如果為true則直接返回null,這樣procedure就會被認(rèn)為執(zhí)行成功。
而bypass就是把這個procedure對象中的這個flag設(shè)為true。這樣stuck的procedure就能夠不再執(zhí)行,后續(xù)的修復(fù)才能繼續(xù)。
返回值為true則是成功,false是失敗。
參數(shù)解析:
-o,--overide
在執(zhí)行bypass之前先會嘗試去拿idLock,如果procedure還在運(yùn)行就會超時返回null,但是設(shè)置了這個參數(shù),即使拿不到idLock也會去將procedure的bypass flag設(shè)為true。
-r, --recursive
在bypass一個procedure時也會將這個procedure的所有子procedure進(jìn)行遞歸bypass是。例如我們bypass一個對table schema修改的procedure,就需要加上-r參數(shù),才能把這個操作的所有子procedure都bypass掉。
-w, --lockWait
上面提到的等到idLock的超時時間配置,默認(rèn)為1ms。
5.2 assigns [OPTIONS] <ENCODED_REGIONNAME> ...
將一個或多個region再次隨機(jī)assign到別的機(jī)器上,返回值時創(chuàng)建的pid則為成功,-1則為失敗。
參數(shù)解析:
-o, --override
這里的override跟bypass的override不同,因為assign本身就會創(chuàng)建一個新的procedure,所以肯定是不涉及到拿idLock的,但是這里涉及到資源鎖的問題。因為之前卡住的資源鎖即使在bypass后也不會釋放(用于fence, 防止更多未知的錯誤操作),所以需要加一個-o去手動釋放這個資源鎖。
下面,我們實際運(yùn)行一下這個命令,感受其作用。
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar assigns -o leo_test,,1588902855503.596a8c918380a9fb55ed64ecf716ecd6.
- leo_test,,1588902855503.596a8c918380a9fb55ed64ecf716ecd6. 這個是我測試表,leo_test的一個region的encoded_name
命令執(zhí)行的結(jié)果是:

返回值為-1,說明命令運(yùn)行失敗。
十有八九是我的region name指定錯了,重新運(yùn)行如下命令。
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar assigns -o 596a8c918380a9fb55ed64ecf716ecd6
命令執(zhí)行的結(jié)果是:

可以看到,成功返回了此次procedure的ID,觀察HBase自帶的監(jiān)控界面。

HBCK2的命令提交成功后,監(jiān)控界面會顯示此次操作的記錄,里面可以查看命令運(yùn)行的詳細(xì)狀態(tài)。
查看表的監(jiān)控界面,發(fā)現(xiàn)我們操作的region依然在72那臺機(jī)器上,看起來好像沒有任何變化。不知道是不是由于我們測試的表只有一個region的緣故,于是,我又測試了一張有17個region的表。
除了master有這樣的日志之外,還是沒有任何效果。

暫時實在搞不明白這條命令的具體效果,以后再慢慢研究吧,接著來看下一個核心功能。
5.3 unassigns [OPTIONS] <ENCODED_REGIONNAME> ...
將一個或多個region unassign,返回值是創(chuàng)建的pid則為成功,-1則為失敗。
參數(shù)解析:
-o,--override,與assigns的一致
5.4 setTableState <TABLE> <STATE>
可能的table狀態(tài), ENABLED, DISABLED, DISABLING, ENABLING
在table的狀態(tài)和所有的region狀態(tài)不一致時可以用這個命令進(jìn)行修復(fù)
5.5 serverCrashProcedures <ServerName> ...
手動schedule一個或多個serverCrashProcedure, 如果有serverCrashProcedure沒有執(zhí)行成功,但是procedure log已經(jīng)丟失了,那么可以利用這個命令進(jìn)行修復(fù)。返回值為創(chuàng)建的pid則為成功,-1則為失敗。
patch在HBASE-21393[3],目前這個功能在release版本還沒有。

看樣子應(yīng)該能用,可現(xiàn)在就是不知道咋用。
6. 利用HBCK2來查找集群的問題
6.1 canary tool
模擬用戶的讀寫請求,去訪問集群上的表。當(dāng)我們需要檢查集群meta上記錄的region assignment跟實際region server上打開的region是否一致時,可以使用這個命令去檢查:
hbase canary -f false -t 6000000
nohup hbase canary -f false -t 6000000 > /data/leo_jie/hbase.log 2>&1 &
這個命令會向meta上的記錄的每個region發(fā)送一個get請求,將-f設(shè)為false是為了不在遇到第一個錯誤時退出,-t則是這個命令的超時時間,我們設(shè)成了6000秒。在執(zhí)行完成以后可以通過grep ERROR來找到那些有問題的region。
需要注意的是因為是模擬客戶端發(fā)送的get請求,最好將HBase的客戶端超時時間和超時次數(shù)配的小一些,否則會很慢。
PS: canary 本身也很適合用來作為集群可用性的監(jiān)控,有興趣的同學(xué)可以去了解一下。
cat /data/leo_jie/hbase.log | grep ERROR
grep ERROR 來發(fā)現(xiàn)是否有異常信息。
6.2 頁面狀態(tài)
其實大部分的信息都會在master的頁面上展示出來,我們來詳細(xì)的介紹一下:

可以檢查當(dāng)前所有沒有執(zhí)行完的procedure以及所有資源鎖,當(dāng)我們想要assign或者unassign一個region時,需要先去檢查下是由有別的procedure已經(jīng)占有了這個資源鎖,如果是的話需要現(xiàn)將那個procedure bypass掉,或者等待那個procedure釋放鎖。

可以看到EXCLUSIVE的lock只有region級別的,圖中紅框圈出來的就是占有這個鎖的procedure id以及它的parent procedure id, 由此我們知道如果想要重新assign/unassign這個region,那么一定要bypass這個procedure。
同理,當(dāng)Locks這塊沒有任何EXLUSIVE鎖時,我們可以放心的去執(zhí)行操作而不用擔(dān)心被卡住。
以上內(nèi)容節(jié)選自,HBase指南 | HBase 2.0之修復(fù)工具HBCK2運(yùn)維指南,因為我在本地測試的時候,沒有重現(xiàn)這種鎖占用的情況。
6.3 OPENING/CLOSING region的查找
branch-2.0 上最容易出現(xiàn)的問題就是region卡在了OPENNING/CLOSING狀態(tài),一般處于這兩種狀態(tài)的region都會在rit的隊列中,可以通過點擊頁面上的鏈接拿到所有的region以及對應(yīng)的procedure id。

可以看到現(xiàn)在有17個region處在transition中,我們可以點擊紅框圈住的這個鏈接,會展示所有的region。

因為我們最后是希望通過HBCK2來進(jìn)行處理,那么最好是可以復(fù)制粘貼需要處理的region或者procedure, 所以可以點擊圈出的這兩個按鈕,會以text形式展示所有region或者所有procedure。

以上內(nèi)容依舊是節(jié)選,因為沒遇到RIT的情況,同時,我們也不希望遇見。??
6.4 Master的日志
stuck的region會打印以下日志:
WARN [ProcExecTimeout] org.apache.hadoop.hbase.master.assignment.AssignmentManager: STUCK Region-In-Transition rit=OPENING, location=c4-hadoop-tst-st99.bj,42900,1542148656901, table=test_modify, region=8d81f74b324d0503c3fc87f34e9a17cb
7.解決問題
定位到問題之后,我們需要解決問題。
7.1 解決region卡在OPENING/CLOSING 狀態(tài)
首先找到這些region對應(yīng)的pid, 然后執(zhí)行bypass, 檢查是否鎖都釋放了,如果釋放了就再assign一遍,如果需要close,就再unassign一次。
7.2 對table的修改有問題如何回退
找到這個修改的root procedure, bypass -or來bypass所有相關(guān)的procedure, 利用table unset來重置meta,因為bypass之后資源鎖還是沒有釋放,所以需要手動加上override參數(shù)再去全部assigns一遍
7.3 Master起不來
日志里一般會有這個:
WARN org.apache.hadoop.hbase.master.HMaster: hbase:meta,,1.1588230740 is NOT online; state={1588230740 state=CLOSING, ts=1538456302300, server=ve1017.example.org,22101,1538449648131}; ServerCrashProcedures=true. Master startup cannot progress, in holding-pattern until region onlined.
手動去assign一下meta表即可,hbase:meta表的encoded name是一個時間戳,比如上面日志的encoded name就是1588230740
另外hbase:namespace表沒有online也會造成這個問題,同樣需要我們?nèi)ナ謩觓ssign一下
7.4 table卡在disabling狀態(tài)
因為要求是所有region都disabled, 那么解決辦法可以是手動把沒有closed的region根據(jù)case1來解決。如果所有region都已經(jīng)是closed狀態(tài)了,那么我可以利用setTableState手動將表的狀態(tài)設(shè)為DISABLED。之后再drop都是安全的了。
8. 總體的解決思路
其實HBase-2.x版本的運(yùn)維思路很簡單,因為使用了procedure,集群出現(xiàn)meta跟regionserver不一致的狀態(tài)是很少的,一般都是有procedure出問題了。那么我們主要就是看怎么解決這個有問題的procedure。
如果是table/namespace級別的修改,因為設(shè)計到很多region的鎖,如果需要bypass的話需要找到root procedure然后使用bypass -or.
如果只是region級別的問題,則bypass -o即可。
bypass之后檢查locks的頁面,看看是不是鎖都釋放了,如果沒有鎖了則根據(jù)需求進(jìn)行assign或者unassign,或者對table的屬性進(jìn)行還原。
9. 參考鏈接
文中很多解決問題的思路參考了一下博客,后續(xù)實踐中如果遇到此類問題,將會進(jìn)行更加詳細(xì)的分析和總結(jié),然后補(bǔ)充文檔。