HBase故障不可用,如何捞出数据?

目录

背景

原理

操作步骤

QA

结论

彩蛋


背景

        公司生产环境HBase集群发生了严重故障,导致HBase所有库表都无法读写,只得临时启用了新集群,但老集群的历史数据也非常重要,需要捞出并尽量还原出来,笔者临危受命,着手进行技术调研尝试恢复数据。调研HBase了解到写入HBase的数据最终都是以HFile文件的形式存储在HDFS上,那么直接根据HFile文件而非通过HBase API完成数据还原是否可行呢?答案是肯定的。HBase官网推荐的直接加载HFile数据的方式就是Bulk Loading,相比HBase API,Bulkload使用更少的CPU周期和网络资源从而性能更高,本文就使用Bulkload恢复历史数据的整个过程展开分享。

原理

        首先,我们了解下HBase的存储机制,每张HBase表是由1个或多个Region组成,每个Region有1个或多个Store,每个Store则对应一个列族的数据,由一个MemStore和0至多个StoreFile组成,数据写入HBase的时候首先会放入MemStore,当MemStore满了以后flush成一个StoreFile,而StoreFile是以HFile的格式保存在HDFS上,一般HBase的数据保存在HDFS固定目录下,即配置hbase-site.xml里hbase.rootdir的属性值,缺省是/hbase, hbase启动时就会自动创建该目录,包含的各种文件结构如下:

root@xxx:~#hadoop fs -ls /hbase
Found 13 items
drwxr-xr-x   - hbase hadoop          0 2022-01-14 11:41 /hbase/.hbase-snapshot
drwxr-xr-x   - hbase hadoop          0 2021-10-09 17:13 /hbase/.hbck
drwxr-xr-x   - hbase hadoop          0 2021-10-15 17:01 /hbase/.tmp
drwxr-xr-x   - hbase hadoop          0 2022-12-26 19:26 /hbase/MasterProcWALs
drwxr-xr-x   - hbase hadoop          0 2022-12-09 18:46 /hbase/WALs
drwxr-xr-x   - hbase hadoop          0 2021-10-12 16:39 /hbase/archive
drwxr-xr-x   - hbase hadoop          0 2021-10-09 17:13 /hbase/corrupt
drwxr-xr-x   - hbase hadoop          0 2022-12-15 11:43 /hbase/data
-rw-r--r--   3 hbase hadoop         42 2021-10-09 17:13 /hbase/hbase.id
-rw-r--r--   3 hbase hadoop          7 2021-10-09 17:13 /hbase/hbase.version
drwxr-xr-x   - hbase hadoop          0 2021-10-09 17:13 /hbase/mobdir
drwxr-xr-x   - hbase hadoop          0 2022-12-26 20:21 /hbase/oldWALs
drwx--x--x   - hbase hadoop          0 2022-12-16 14:57 /hbase/staging

举一个真实的栗子如下:

 /hbase/data/default/panTag/3ef7bc9993776a2f868dd387e40d1954/cf/91866a42308b4734985c23c33afcd3d3

        其中,/hbase/data即为所有HBase表数据的父目录。default为表所属缺省Namespace,panTag是表名,3ef7bc9993776a2f868dd387e40d1954为随机MD5字符串,属于Region ID的一部分,cf是列族名,91866a42308b4734985c23c33afcd3d3也是MD5字符串,表示StoreFile ID。

可以通过hfile -s命令查看该HFile文件的统计信息,如下:

root@xxx:~#hbase hfile -s /hbase/data/default/panTag/3ef7bc9993776a2f868dd387e40d1954/cf/91866a42308b4734985c23c33afcd3d3
Stats:
   Key length:
               min = 39
               max = 64
              mean = 44.05
            stddev = 10.04
            median = 39.00
              75% <= 39.00
              95% <= 64.00
              98% <= 64.00
              99% <= 64.00
            99.9% <= 64.00
             count = 281816
   Row size (bytes):
               min = 83
               max = 4466
              mean = 707.00
            stddev = 807.39
            median = 409.00
              75% <= 757.00
              95% <= 2502.55
              98% <= 4168.14
              99% <= 4320.23
            99.9% <= 4465.25
             count = 281816
   Row size (columns):
               min = 1
               max = 1
              mean = 1.00
            stddev = 0.00
            median = 1.00
              75% <= 1.00
              95% <= 1.00
              98% <= 1.00
              99% <= 1.00
            99.9% <= 1.00
             count = 281816
   Val length:
               min = 36
               max = 4684
              mean = 667.73
            stddev = 820.86
            median = 353.00
              75% <= 753.50
              95% <= 2418.60
              98% <= 4096.28
              99% <= 4298.55
            99.9% <= 4679.51
             count = 281816


Key of biggest row: 8114442716031216

如果找到了HFile文件,再使用Bulkload方式加载数据到目标表即可,HFile从HDFS获取并加载到目标HBase集群的流程如下:

操作步骤

  1. 根据Namespace和table名称遍历筛选出源表所有相关HFile文件。

            基于/HBase/data固定前缀路径,再根据Namespace和table名称可拼接出源表的HDFS保存目录,其实,除了HFile文件,/HBase/data路径下还可能包括用于表元数据的.tabledesc子目录和.regioninfo文件、用于恢复WAL日志的recovered.edits子目录等,这些均与HFile数据无关可直接忽略,另外,HFile文件名称是32位长度的16进制MD5散列值,可根据该特点遍历过滤出真正的HFile文件。

  2. 使用Bulkload方式导入到目标表中。

            一般有两种方式,一种是使用CompleteBulkLoad工具实现导入,另一种是使用LoadIncrementalHFiles类编写程序进行导入。提前创建和源表结构一致的目标表,分别使用以上两种方案如下所示:

  •   采用CompleteBulkLoad命令如下:
HADOOP_CLASSPATH=`/usr/bin/hbase classpath`:$(find /usr/lib/hbase/lib -name '*.jar' | xargs echo | tr ' ' ':') hadoop jar /usr/lib/hbase/lib/hbase-mapreduce-2.1.0-cdh6.3.2.jar completebulkload  <生成的HFile文件路径> <目标表名称> 
  • 利用HBase官方提供的LoadIncrementalHFiles类编写自动化工具,核心代码如下:

String table = "<target_table>";
Configuration conf = HBaseConfiguration.create();
Connection hConnection = ConnectionFactory.createConnection(conf);
Admin admin = hConnection.getAdmin();
Table hTable = hConnection.getTable(TableName.valueOf(table));
RegionLocator regionLocator = hConnection.getRegionLocator(TableName.valueOf(table));
LoadIncrementalHFiles loader = new LoadIncrementalHFiles(conf);
loader.doBulkLoad(new Path(loadPath), admin, hTable, regionLocator);

QA

  • 执行Bulkload命令或程序后目标表查不到数据,也没有具体报错信息。

       检查运行HBase命令或程序的用户是否拥有目标表的写入权限。如果权限不足,执行授权命令:grant '<user>' , 'RW' , '<table>'。

  • snappy压缩报错,如Caused by: java.lang.UnsatisfiedLinkError: org.apache.hadoop.util.NativeCodeLoader.buildSupportsSnappy()Z

       源表应该是使用了snappy压缩格式,因为snappy解压缩需要利用libsnappy.so等本地snappy库文件,一般在安装Hadoop时会自动在本地安装该库文件,所以需要在执行时添加该库文件的依赖,不过需要注意的是通过-cp添加本地库依赖是无效的,必须通过指定-Djava.library.path=<snappy本地库路径>或在环境变量中添加export LD_LIBRARY_PATH=<snappy本地库路径>才会生效。

结论

        经过验证,通过HFile文件是可以还原出HBase历史数据的,为公司挽回了损失,其中用到的Bulkload是用于大批量写入HBase数据的比较简单高效的方法,不过有一点需要注意:因为是通过生成好并排过序的HFile文件上传到RegionServer上直接生成数据,所以是不会像HBase API那样记录WAL日志的。

彩蛋

附上自己写的还原HFile数据的运维工具供大家参考,github地址:

HBase HFile还原数据工具https://github.com/bigcatpan/hbase-tool

猜你喜欢

转载自blog.csdn.net/BlogPan/article/details/128461632
今日推荐