HBase2.0 meta信息丢失的修复方法

在HBase入库日志中发现有一个表入库失败,检查HBase服务端后发现该表的meta信息丢失了:

而HDFS上的region还在:

而HBCK工具不支持HBase2.0版本,只好自己写一个修复工具。网上可以搜到前辈们自己编写的一些工具,比如这一篇写的就比较详细 https://blog.csdn.net/xyzkenan/article/details/103476160

我们引用一下,再对个别地方略微讲解。

看一下'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内容相同

接下来就开始动手coding:

获取'hbase:mata'中的Region信息

 1     public Set<String> getMetaRegions(Configuration conf, String tableName) throws Exception {
 2  
 3         Connection conn = ConnectionFactory.createConnection(conf);
 4         Table table = conn.getTable(TableName.valueOf(TABLE));
 5  
 6         PrefixFilter filter = new PrefixFilter(Bytes.toBytes(tableName + ","));
 7  
 8         Scan scan = new Scan();
 9         scan.setFilter(filter);
10  
11         Set<String> metaRegions = new HashSet<>();
12  
13         Iterator<Result> iterator = table.getScanner(scan).iterator();
14         while (iterator.hasNext()) {
15             Result result = iterator.next();
16             metaRegions.add(Bytes.toString(result.getRow()));
17         }
18  
19         conn.close();
20  
21         return metaRegions;
22     }

读取.regioninfo中的Region信息

 1     public Map<String, RegionInfo> getHdfsRegions(Configuration conf, String tablePath) throws Exception {
 2  
 3         FileSystem fs = FileSystem.get(conf);
 4         Path path = new Path(hdfsRootDir + "/data/default/" + tablePath + "/");
 5  
 6         Map<String, RegionInfo> hdfsRegions = new HashMap<>();
 7  
 8         FileStatus[] list = fs.listStatus(path);
 9         for (FileStatus status : list) {
10             if (!status.isDirectory()) {
11                 continue;
12             }
13  
14             boolean isRegion = false;
15             FileStatus[] regions = fs.listStatus(status.getPath());
16             for (FileStatus regionStatus : regions) {
17                 if (regionStatus.toString().contains(REGION_INFO_FILE)) {
18                     isRegion = true;
19                     break;
20                 }
21             }
22  
23             if (!isRegion) {
24                 continue;
25             }
26  
27             RegionInfo hri = HRegionFileSystem.loadRegionInfoFileContent(fs, status.getPath());
28             hdfsRegions.put(hri.getRegionNameAsString(), hri);
29  
30         }
31         return hdfsRegions;
32     }

两者进行对比取差集

1         Set<String> metaRegions = getMetaRegions(configuration, repairTableName);
2  
3         Map<String, RegionInfo> hdfsRegions = getHdfsRegions(configuration, repairTableName);
4  
5         Set<String> hdfsRegionNames = hdfsRegions.keySet();
6  
7         metaRegions.removeAll(hdfsRegionNames);

构造META信息并写入HBase

 1         ServerName[] regionServers = admin.getRegionServers().toArray(new ServerName[0]);
 2         
 3         int rsLength = regionServers.length;
 4         int i = 0;
 5         for (String regionName : hdfsRegionNames) {
 6  
 7             String sn = regionServers[i % rsLength].getServerName();
 8             String[] snSig = sn.split(",");
 9  
10             RegionInfo hri = hdfsRegions.get(regionName);
11             Put info = MetaTableAccessor.makePutFromRegionInfo(hri, EnvironmentEdgeManager.currentTime());
12             info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(SN), Bytes.toBytes(sn));
13             info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(SERVER), Bytes.toBytes(snSig[0] + ":" + snSig[1]));
14             info.addColumn(Bytes.toBytes(FAMILY), Bytes.toBytes(STATE), Bytes.toBytes("OPEN"));
15  
16             table.put(info);
17             i++;
18         }

注意这里的各个region是轮流分配给各个regionServers,具体分配可能和meta信息丢失前不同,但是没关系,一个regionServer管理多个region,映射关系可以改变的,重启HBase服务后会生效,HBase内部也会平衡每个regionServer管理的region数量,也可在hbase shell中手动触发平衡。

使用工具修复后,先验证一下是否生成了新的meta信息:

确认无误,接下来重启所有HBase服务,重启之后会自动生成'info:seqnumDuringOpen'以及'info:serverstartcode'

重启之后,验证修复好的表是否可以读写:

OK,至此基本大功告成,再把工具稍加封装,融入我的组件包内,添加到REST API里,以后再遇到这种问题,发一个POST请求,瞬间修复。

最后还引用一下前辈封装好的工具以供下载使用,https://github.com/darkphoenixs/hbase-meta-repair

自己使用时要略加修改,比如你的hbase.root.dir可能不同,此外,我的HBase服务端虽然是2.0,但是我的修复工具使用的是1.x的包,有些接口略有不同,RegionInfo对应的是HRegionInfo,此外,1.x获取RegionServer使用的是

ServerName[] regionServers = admin.getClusterStatus.getServers().toArray(new ServerName[0]);
原文地址:https://www.cnblogs.com/yudizhao/p/13224863.html