HBase跨集群复制Snapshot失败原因分析及解决

起因

HBase快照在跨集群复制时,经常会出现由于/hbase/.tmp/data/xxx FileNotFoundException导致任务失败 
现还原出错场景,并分析错误原因,给出一些常用的解决方法 

  • 主要原因 
    在创建快照到跨集群复制过程中,部分StoreFile的位置发生了变动,以至不能正常寻址( 使用webhdfs的bug)

场景还原

源集群:HBase 1.2.0-cdh5.10.0 
目标集群:HBase 1.2.0-cdh5.12.1

1. 创建表mytable,2个region,以03为分割,一个列族info

put 6条数据 

put 'mytable','01','info:age','1' 
put 'mytable','02','info:age','2' 
put 'mytable','03','info:age','3' 
put 'mytable','04','info:age','1' 
put 'mytable','05','info:age','1' 
put 'mytable','06','info:age','1'

2. 创建快照mysnapshot,生成以下文件

  • .snapshot 包含了快照信息,即HBaseProtos.SnapshotDescription对象 
    name: "mysnapshot" 
    table: "mytable" 
    creation_time: 1533774121010 
    type: FLUSH 
    version: 2

  • data.manifest 
    包含了hbase表schema、attributes、column_families,即HBaseProtos.SnapshotDescription对象,重点的是store_files信息

3. 修改数据

通过Put 修改一个Region的数据 

put 'mytable','04','info:age','4' 
put 'mytable','05','info:age','5' 
put 'mytable','06','info:age','6'

4. 进行flush,major_compat

模拟跨集群复制过程中出现的大/小合并

 

还原出错

控制台提示,FileNotFoundException,任务失败

 

源代码剖析

1 ExportSnapshot执行复制前会先将.snapshot,data.manifest 复制到目标端 .hbase-snapshot/.tmp/mysnapshot下

2 解析data.manifest,按照storefile进行逻辑切片,map每次会读入一个SnapshotFileInfo的信息,只包含了HFileLink信息,并没有包括具体路径 

3 map阶段 
每读入一个SnapshotFileInfo时,拼接出关于StoreFile可能出现的4个路径,读取时按照该顺序查找 

/datafs/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3 
/datafs/.tmp/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3 
/datafs/mobdir/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3 
/datafs/archive/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3

当map读入数据时,调用ExportSnapshot.ExportMapper#openSourceFile 初始化InputStream的过程中 
通过调用FileLink.tryOpen()方法中,来确定StoreFile的真实路径路径(遍历4个路径,抛出异常说明不存在,继续找下一路径)

在debug中发现,fs为org.apache.hadoop.hdfs.web.WebHdfsFileSystem对象 
遗憾的是,WebHdfsFileSystem调用getPos()时,不会抛出异常,因此获取到如下路径(文件实际存在于archive) 

/datafs/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3 

并将 该路径设置为currentPath(下一次会用到,避免重复判定)
当InputStream.read(buffer)时,调用FileLink.read() 
 
由于初始化时,并没有使用正确的路径,因此 in.read()时,抛出FileNotFoundException(第一次) 
继续调用tryOpen().read()方法遍历4个路径,此时 currentPath为 data路径跳过,使用下一个路径(文件仍在archive下) 

/datafs/.tmp/data/default/mytable/c48642fecae3913e0d09ba236b014667/info/3c5e9ec890f04560a396040fa8b592a3

read错误路径,再次抛出FileNotFoundException(第二次),此异常向上抛出,task失败,观察map日志,可看到 

红线之下的FileNotFoundException,即为read()时,抛出的两次异常 
红线之上File does not exist 为ExportSnapshot 系调用 getSourceFileStatus产生,可以观察到在遍历 data/.tmp/mobdir 后寻找到了正确路径archive(未打印出)

解决思路

综上:查找StoreFile时只会查找data、.tmp目录,不会查找archive目录 
因此解决思路上,一是避免StoreFile出现在archive下,二是能正确获取到archive路径

避免StoreFile出现在archive

根据生产经验,在数据大量写入过程中,Region下不断生成StoreFile,当StoreFile数量达到阈值时,触发大/小合并 
被合并的StoreFile文件移动到了archive文件下,可使用以下几个方法避免复制时大/小合并

  1. 对表进行major_compact后再建快照
  2. 如果表可以接受一段时间的不可用,几分钟到几十分钟不等,可对表进行disable后再操作
  3. 或者适当调大 hbase.hstore.compaction.Threadhold(表写入不频繁下)
  4. 根据业务情况,尽可能大的错开数据写入与复制的间隔(等待大/小合并自动完成)

避免使用webhdfs

使用hdfs时,可以正常的抛出异常(未具体使用)

修复源码bug

使得在寻址过程中,可正确读到archive文件夹 
借鉴getSourceFileStatus(),在for中加一行 fs.getFileStatus(),遍历时正常抛出FileNotFoundException 

将ExportSnapshot抽出,重新组织HFileLink,FileLink,WALLink依赖 
打包成一个hadoop jar,避免影响其它功能

参考:https://blog.csdn.net/t894690230/article/details/52121613

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值