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

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

把該jar包上傳到集群隨便一個目錄下。
3. 測試命令是否可以正常使用
開始使用HBCK2的命令,最直接的使用方式:
./bin/hbase hbck -j <jar包地址> <命令>
使用HBCK2禁用啟用測試表。
運行禁用表命令:
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 改變表狀態的命令
- leo_test 表名
- DISABLED 禁用狀態
看圖,表的狀態已經被更改為DISABLED

運行啟用表命令:
hbase hbck -j hbase-hbck2-1.1.0-SNAPSHOT.jar setTableState leo_test ENABLED
看圖,表的狀態已經被更改為ENABLED

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

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

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

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

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

看樣子應該能用,可現在就是不知道咋用。
6. 利用HBCK2來查找集群的問題
6.1 canary tool
模擬用戶的讀寫請求,去訪問集群上的表。當我們需要檢查集群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發送一個get請求,將-f設為false是為了不在遇到第一個錯誤時退出,-t則是這個命令的超時時間,我們設成了6000秒。在執行完成以后可以通過grep ERROR來找到那些有問題的region。
需要注意的是因為是模擬客戶端發送的get請求,最好將HBase的客戶端超時時間和超時次數配的小一些,否則會很慢。
PS: canary 本身也很適合用來作為集群可用性的監控,有興趣的同學可以去了解一下。
cat /data/leo_jie/hbase.log | grep ERROR
grep ERROR 來發現是否有異常信息。
6.2 頁面狀態
其實大部分的信息都會在master的頁面上展示出來,我們來詳細的介紹一下:

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

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

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

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

以上內容依舊是節選,因為沒遇到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 狀態
首先找到這些region對應的pid, 然后執行bypass, 檢查是否鎖都釋放了,如果釋放了就再assign一遍,如果需要close,就再unassign一次。
7.2 對table的修改有問題如何回退
找到這個修改的root procedure, bypass -or來bypass所有相關的procedure, 利用table unset來重置meta,因為bypass之后資源鎖還是沒有釋放,所以需要手動加上override參數再去全部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也會造成這個問題,同樣需要我們去手動assign一下
7.4 table卡在disabling狀態
因為要求是所有region都disabled, 那么解決辦法可以是手動把沒有closed的region根據case1來解決。如果所有region都已經是closed狀態了,那么我可以利用setTableState手動將表的狀態設為DISABLED。之后再drop都是安全的了。
8. 總體的解決思路
其實HBase-2.x版本的運維思路很簡單,因為使用了procedure,集群出現meta跟regionserver不一致的狀態是很少的,一般都是有procedure出問題了。那么我們主要就是看怎么解決這個有問題的procedure。
如果是table/namespace級別的修改,因為設計到很多region的鎖,如果需要bypass的話需要找到root procedure然后使用bypass -or.
如果只是region級別的問題,則bypass -o即可。
bypass之后檢查locks的頁面,看看是不是鎖都釋放了,如果沒有鎖了則根據需求進行assign或者unassign,或者對table的屬性進行還原。
9. 參考鏈接
文中很多解決問題的思路參考了一下博客,后續實踐中如果遇到此類問題,將會進行更加詳細的分析和總結,然后補充文檔。
可能的table狀態, ENABLED, DISABLED, DISABLING, ENABLING
在table的狀態和所有的region狀態不一致時可以用這個命令進行修復
5.5 serverCrashProcedures
...
手動schedule一個或多個serverCrashProcedure, 如果有serverCrashProcedure沒有執行成功,但是procedure log已經丟失了,那么可以利用這個命令進行修復。返回值為創建的pid則為成功,-1則為失敗。
patch在HBASE-21393[3],目前這個功能在release版本還沒有。

看樣子應該能用,可現在就是不知道咋用。
6. 利用HBCK2來查找集群的問題
6.1 canary tool
模擬用戶的讀寫請求,去訪問集群上的表。當我們需要檢查集群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發送一個get請求,將-f設為false是為了不在遇到第一個錯誤時退出,-t則是這個命令的超時時間,我們設成了6000秒。在執行完成以后可以通過grep ERROR來找到那些有問題的region。
需要注意的是因為是模擬客戶端發送的get請求,最好將HBase的客戶端超時時間和超時次數配的小一些,否則會很慢。
PS: canary 本身也很適合用來作為集群可用性的監控,有興趣的同學可以去了解一下。
cat /data/leo_jie/hbase.log | grep ERROR
grep ERROR 來發現是否有異常信息。
6.2 頁面狀態
其實大部分的信息都會在master的頁面上展示出來,我們來詳細的介紹一下:

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

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

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

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

以上內容依舊是節選,因為沒遇到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 狀態
首先找到這些region對應的pid, 然后執行bypass, 檢查是否鎖都釋放了,如果釋放了就再assign一遍,如果需要close,就再unassign一次。
7.2 對table的修改有問題如何回退
找到這個修改的root procedure, bypass -or來bypass所有相關的procedure, 利用table unset來重置meta,因為bypass之后資源鎖還是沒有釋放,所以需要手動加上override參數再去全部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也會造成這個問題,同樣需要我們去手動assign一下
7.4 table卡在disabling狀態
因為要求是所有region都disabled, 那么解決辦法可以是手動把沒有closed的region根據case1來解決。如果所有region都已經是closed狀態了,那么我可以利用setTableState手動將表的狀態設為DISABLED。之后再drop都是安全的了。
8. 總體的解決思路
其實HBase-2.x版本的運維思路很簡單,因為使用了procedure,集群出現meta跟regionserver不一致的狀態是很少的,一般都是有procedure出問題了。那么我們主要就是看怎么解決這個有問題的procedure。
如果是table/namespace級別的修改,因為設計到很多region的鎖,如果需要bypass的話需要找到root procedure然后使用bypass -or.
如果只是region級別的問題,則bypass -o即可。
bypass之后檢查locks的頁面,看看是不是鎖都釋放了,如果沒有鎖了則根據需求進行assign或者unassign,或者對table的屬性進行還原。
9. 參考鏈接
文中很多解決問題的思路參考了一下博客,后續實踐中如果遇到此類問題,將會進行更加詳細的分析和總結,然后補充文檔。
