問題起因
必須先吐槽一下 Cloudera 6.x 和 Hbase 2.0 太坑了!
不久前生産上的一套Hbase叢集出現著名的RIT(Regions in Transition)問題。
檢視hbase web ui

于是通過hbck指令檢視一下叢集狀态,果然好多inconsistency
...
ERROR: Region { meta => XXX,XXX:,1573019231000.ff2aecaf28917792395c341d01e0b8cc., hdfs => hdfs://nameservice1/hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc, deployed => , replicaId => 0 } not deployed on any region server.
...
ERROR: Found inconsistency in table XXX
...
9 inconsistencies detected.
Status: INCONSISTENT
看到錯誤提示問題明顯了,這個Region在hdfs中有資料檔案但沒有依賴任何Region Server,原因可能region被原來的Region Server unassigned了,但是還沒有被assigned到一個新的Region Server上。
那麼嘗試用
hbase hbck -repair
和
hbase hbck -fixMeta -fixAssignments
來修複吧,于是就有了下面的提示,hbase2.0+以後hbck的所有修複功能全都不支援...
-----------------------------------------------------------------------
NOTE: As of HBase version 2.0, the hbck tool is significantly changed.
In general, all Read-Only options are supported and can be be used
safely. Most -fix/ -repair options are NOT supported. Please see usage
below for details on which options are not supported.
-----------------------------------------------------------------------
NOTE: Following options are NOT supported as of HBase version 2.0+.
UNSUPPORTED Metadata Repair options: (expert features, use with caution!)
-fix Try to fix region assignments. This is for backwards compatiblity
-fixAssignments Try to fix region assignments. Replaces the old -fix
-fixMeta Try to fix meta problems. This assumes HDFS region info is good.
-fixHdfsHoles Try to fix region holes in hdfs.
...
UNSUPPORTED Metadata Repair shortcuts
-repair Shortcut for -fixAssignments -fixMeta -fixHdfsHoles -fixHdfsOrphans -fixHdfsOverlaps -fixVersionFile -sidelineBigOverlaps -fixReferenceFiles-fixHFileLinks
-repairHoles Shortcut for -fixAssignments -fixMeta -fixHdfsHoles
既然hbck不支援,覺得hbase總得有解決方案吧,科學上網後發現hbase2.0+提供了一個叫hbck2工具,不過得自己編譯麻煩了點。
克隆下來準備動手編譯發現不對,于是仔細看了一下hbck2的介紹,
最低支援版本2.0.3和2.1.1WTF......這就是個黑洞啊,還有你就不能把支援的版本号字型放大點嗎!
修複方案
吐槽過後,還是得想解決辦法啊:
- 更新Hbase版本
- 目前這種情況是根本無法更新的,存量資料怎麼辦,就算資料可以重入,目前使用的hbase是CDH版,Cloudera 6.x版本內建的hbase隻有2.0.0和2.1.0版本,還是黑洞。。。此方案行不通。
- 暴力删除hbase資料
- 暴力删除資料,格式化hdfs,删除hbasemeta資料,删除zookeeper記錄,這和重新部署一套hbase差不多了,但是前提是資料可以重入或者允許清除,那以後怎麼辦,總不能一遇到問題就删庫吧,生産上面的資料一般都比較敏感根本不能删。。。此方案行不通。
- 寫個工具修複hbase
- 看來隻能這樣了。。。
修複步驟
回到最初的錯誤提示,思考一下,如果Region下資料檔案在hdfs中存在,那是否可以通過.regioninfo檔案(hdfs存儲hbase region資訊的檔案)擷取Region資訊,同時讀取'hbase:meta'表中的Region資訊,進行對比取差集就是要修複的Region,然後将需要修複的Region資訊再寫入到'hbase:meta'中。
按照這個思路,先驗證一下hdfs
檢測一下hbase的block是否完整
hdfs fsck /hbase
Status: HEALTHY
Number of data-nodes: 12
Number of racks: 1
Total dirs: 4650
Total symlinks: 0
...
The filesystem under path '/hbase' is HEALTHY
檢查一下.regioninfo檔案是否完整
hadoop fs -ls /hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc
Found 4 items
-rw-r--r-- 3 hbase hbase 65 2019-10-26 18:29 /hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc/.regioninfo
drwxr-xr-x - hbase hbase 0 2019-11-26 09:37 /hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc/.tmp
drwxr-xr-x - hbase hbase 0 2019-11-26 13:59 /hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc/0
drwxr-xr-x - hbase hbase 0 2019-10-26 18:29 /hbase/data/default/XXX/ff2aecaf28917792395c341d01e0b8cc/recovered.edits
再看一下'hbase:meta'中的存儲結構:
列名 | 說明 |
---|---|
info:state | Region狀态 |
info:sn | Region Server Node,由 server和serverstartcode組成,如slave1,16020,1557998852385 |
info:serverstartcode | Region Server啟動Code,實質上就是Region Server啟動的時間戳 |
info:server | Region Server 位址和端口,如slave1:16020 |
info:seqnumDuringOpen | 表示Region線上時長的一個二進制串 |
info:regioninfo | Region Info,和.regioninfo内容相同 |
OK,覺得這個方案可行,接下來就開始動手coding吧
擷取'hbase:mata'中的Region資訊
public Set<String> getMetaRegions(Configuration conf, String tableName) throws Exception {
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf(TABLE));
PrefixFilter filter = new PrefixFilter(Bytes.toBytes(tableName + ","));
Scan scan = new Scan();
scan.setFilter(filter);
Set<String> metaRegions = new HashSet<>();
Iterator<Result> iterator = table.getScanner(scan).iterator();
while (iterator.hasNext()) {
Result result = iterator.next();
metaRegions.add(Bytes.toString(result.getRow()));
}
conn.close();
return metaRegions;
}
讀取.regioninfo中的Region資訊
public Map<String, RegionInfo> getHdfsRegions(Configuration conf, String tablePath) throws Exception {
FileSystem fs = FileSystem.get(conf);
Path path = new Path(hdfsRootDir + "/data/default/" + tablePath + "/");
Map<String, RegionInfo> hdfsRegions = new HashMap<>();
FileStatus[] list = fs.listStatus(path);
for (FileStatus status : list) {
if (!status.isDirectory()) {
continue;
}
boolean isRegion = false;
FileStatus[] regions = fs.listStatus(status.getPath());
for (FileStatus regionStatus : regions) {
if (regionStatus.toString().contains(REGION_INFO_FILE)) {
isRegion = true;
break;
}
}
if (!isRegion) {
continue;
}
RegionInfo hri = HRegionFileSystem.loadRegionInfoFileContent(fs, status.getPath());
hdfsRegions.put(hri.getRegionNameAsString(), hri);
}
return hdfsRegions;
}
兩者進行對比取差集
Set<String> metaRegions = getMetaRegions(configuration, repairTableName);
Map<String, RegionInfo> hdfsRegions = getHdfsRegions(configuration, repairTableName);
Set<String> hdfsRegionNames = hdfsRegions.keySet();
metaRegions.removeAll(hdfsRegionNames);
構造META資訊并寫入HBase
ServerName[] regionServers = admin.getRegionServers().toArray(new ServerName[0]);
int rsLength = regionServers.length;
int i = 0;
for (String regionName : hdfsRegionNames) {
String sn = regionServers[i % rsLength].getServerName();
String[] snSig = sn.split(",");
RegionInfo hri = hdfsRegions.get(regionName);
Put info = MetaTableAccessor.makePutFromRegionInfo(hri, EnvironmentEdgeManager.currentTime());
info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(SN), Bytes.toBytes(sn));
info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(SERVER), Bytes.toBytes(snSig[0] + ":" + snSig[1]));
info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(STATE), Bytes.toBytes("OPEN"));
table.put(info);
i++;
}
重新開機Region Server 和 Hbase Master,重新開機之後會自動生成'info:seqnumDuringOpen'以及'info:serverstartcode'
工具開發完成後,找了個環境驗證了一下,沒出什麼問題,接下來就部署到生産上試試了,反正hbase已經這個樣子,死馬當司馬懿吧。
先用了個region不多的表試驗,發現可以呀,然後陸續把所有錯誤的表都修複一遍,重新開機hbase,接下來就是見證BUG的時刻:
...
0 inconsistencies detected.
Status: OK
hbase修複完成 此處有掌聲
修複工具
本着開源精神,工具已上傳GitHub :
hbase-meta-repair