记录HBase手动删除Hadoop备份(archive)文件后,引发Hbase写入数据出错等一系列问题处理

  由于需要规范HBase数据表命名,对测试环境的数据进行了重命名操作。

  停掉所有服务后执行下面改名操作

# 禁用活跃用户表
disable 'DC_XXL:ACTIVE_USERS'
# 创建快照
snapshot 'DC_XXL:ACTIVE_USERS', 'tony_snapshot'
# 克隆快照为新的表(使用新名称)
clone_snapshot 'tony_snapshot', 'DC_XXL:ACTIVE_USERS_LOG'
# 按命名空间查看克隆的表是否存在
list_namespace_tables 'DC_XXL'
# 查看快照
list_snapshots
# 删除快照
delete_snapshot 'tony_snapshot'
# 查看旧表详情
desc 'DC_XXL:ACTIVE_USERS' 
# 查看新表详情,比较两个表是否一致
desc 'DC_XXL:ACTIVE_USERS_LOG'
# 禁用旧表
disable "DC_XXL:ACTIVE_USERS"
# 删除旧表
drop 'DC_XXL:ACTIVE_USERS'

  然后重新启动测试服务。

  操作完后发现测试服务器的存储空间不足,想要删除一些数据占用,使用df -h查看各服务器的磁盘空间占用情况,发现Hadoop存储目录已占用了90%以上的空间,所以顺便使用命令查看一下Hadoop的空间使用情况

# 查看hadoop根目录各文件夹占用空间
hadoop dfs -du -h /
# 查看hbase占用空间
hadoop dfs -du -h /hbase

  通过命令一层层查看,可以发现主要是hbase占用了存储,而刚刚执行前面的命令操作后,在hbase目录下面发现主要存储空间占用的目录有:data(项目数据表存储目录)与 archive(存档目录),而archive目录一般存储的是备份用的,理论上来说是可以直接删除,所以网上查了一些资料说没问题后,就直接使用 rmr(hadoop dfs -rmr /hbase/archive/data/DC_XXL/ACTIVE_USERS)命令将里面的存档文件删除了,没想到引发了一系列的故障......

  过了一会继续查看磁盘空间占用,发现磁盘使用在持续快速增长,很快有的服务器已达到100%

  使用 hadoop dfs -du -h /hbase 查看发现,MasterProcWALs 目录突然间多了几十G,经查询这是HBase状态日志目录,进去将它们全部删除,发现磁盘占用还是100%没有变化

  继续排查,使用 hadoop dfs -du -h / 发现,原来直接使用rmr删除后,hadoop会将文件移动到 /user/root/.Trash/Current/hbase/ 这个垃圾站目录下面

  而这时在查看服务运行日志时,也发现了大量的IO异常

Hbase_thrift.IOError: IOError(message=b'org.apache.hadoop.hbase.client.RetriesExhaustedException: Failed after attempts=16, exceptions:
Mon Jul 06 20:01:52 CST 2020, RpcRetryingCaller{globalStartTime=1594036912662, pause=100, maxAttempts=16}, org.apache.hadoop.hbase.NotServingRegionException: org.apache.hadoop.hbase.NotServingRegionException: DC_XXL:ACTIVE_USERS_LOG,4,1593765189585.73133efd2d876b7f7edabc3ab6709cae. is not online on slave2,16020,1594035938293
    at org.apache.hadoop.hbase.regionserver.HRegionServer.getRegionByEncodedName(HRegionServer.java:3249)
    at org.apache.hadoop.hbase.regionserver.HRegionServer.getRegion(HRegionServer.java:3226)
    at org.apache.hadoop.hbase.regionserver.RSRpcServices.getRegion(RSRpcServices.java:1414)
    at org.apache.hadoop.hbase.regionserver.RSRpcServices.get(RSRpcServices.java:2429)
......

  从日志中可以看到,是由于写入数据时,所要写入的region下线所引发的IO异常,在浏览器中进入HBase web管理器(http://master:16010),可以看到所有节点都是在线的,拉到 Tables 位置,查看对应的数据表状态,会发现该表的Other Regions标识了出现问题的数量。

  经过查找资料与思考分析,执行快照操作,HBase会在HDFS中创建一个和unix硬链接相同的存储文件,而执行镜像克隆操作时,实际上新表与旧表共用相同的数据块,新表只在data目录创建新表文件,但并不会复制region,只是通过linkfile定位旧表文件地址。当删除旧表以后,HBase应该会将旧表数据移动到 archive 目录下面,只有在新数据写入并提交compact时,才会数据迁移到新表文件中。所以执行快照和克隆操作是秒级,几百G的数据执行命令后立马结果就出来了。

  而我直接删除了备份文件,数据并没有迁移完,导致某些region直接丢失了。

  随后将回收站的文件重新移动到 archive 目录下面,使用 hbck 命令修复,发现修复失败,由于是测试数据只需要从kafka中生成最近一周的就可以了,且旧数据占用太多空间需要清理,所以没有继续研究修复,直接将它清除,决定创建新表运行相关服务批量重新生成测试数据。

  进入hbase shell中,执行命令

disable 'DC_XXL:ACTIVE_USERS_LOG'

  发现命令卡死,直到超时才退出,发现数据表禁用不了也删除不了。

  登录 zookeeper ,删除对应的数据

# 连接zookeeper服务
/usr/local/zookeeper/bin/zkCli.sh -server master:2181
# 查看hbase数据表
ls /hbase/table
# 删除数据表
rmr /hbase/table/DC_XXL:ACTIVE_USERS_LOG

  删除Hadoop存储的数据

# 查看hadoop的dfs文件
hadoop dfs -du -h /hbase/data/DC_XXL
# 删除文件
hadoop dfs -rmr /hbase/data/DC_XXL/ACTIVE_USERS_LOG
# 清除垃圾站文件
hadoop dfs -rmr /user/root/.Trash/Current/hbase/data/DC_XXL/ACTIVE_USERS_LOG

  再次进入hbase shell,输入list已查看不到数据表了,输入命令创建新表

create 'DC_XXL:ACTIVE_USERS_LOG',{NAME=>'c',COMPRESSION=>'lz4',VERSIONS=>1},SPLITS=>['2','4','6','9']

  这时直接提示:ERROR: Table already exists 异常信息,经过排查发现原来meta表还存储了数据表以及对应的region信息,需要一一清除干净才行

# 扫描meta表,查找当前数据表相关记录
scan 'hbase:meta',{STARTROW=>'DC_XXL:ACTIVE_USERS_LOG',ENDROW=>'DC_XXL:ACTIVE_USERS_LO~'}
# 删除表记录命令(这一条命令必须在shell执行,脚本可能删不干净)
deleteall 'hbase:meta','DC_XXL:ACTIVE_USERS_LOG'
# 记录量少的话可以手动一条条删除
......

  批量删除 hbase:meta表数据表相关记录脚本

import happybase

connect = happybase.Connection(host='master', port=9090, timeout=300000, autoconnect=True, compat='0.98', transport='buffered', protocol='binary')

def scan(table, row_prefix=None, columns=None):
    t = happybase.Table(table, connect)
    scan = t.scan(row_prefix=row_prefix, columns=columns)
    data = []
    for key, value in scan:
        result = {row.decode().replace('c:', '').lower(): value[row].decode() for row in value}
        result['pk'] = key.decode()
        data.append(result)
    return data

def delete(table, rowkey):
    t = happybase.Table(table, connect)
    t.delete(rowkey)

if __name__ == '__main__':
    columns = ['info:server']
    row_prefix = 'DC_XXL:ACTIVE_USERS_LOG'.encode()
    result = scan('hbase:meta', row_prefix, columns=columns)
    print(len(result))
    for row in result:
        pk = row.get('pk')
        print(pk)
        delete('hbase:meta', pk)

  脚本执行成功后,需要在shell中执行前面的scan语句检查一次,看看是否全部都删除干净

  然后重启hbase服务,进入shell中执行创建数据表语句,这次就可以执行成功了(不重启hbase服务,可能会影响数据表状态,然后产生大量的异常状态记录占用存储空间)

  

  在这次事件中出现了几次错误操作,导致本次故障。由于之前也试过多次改名,并没有出现问题,导致本次操作时过于轻心。没有深入了解快照和克隆快照的底层原理,而网上查到的 archive 相关文章在不了解其背景的情况下,就以为可以直接删除文件,导致异常的发生。当存储空间不足时,没有全面排查了解存储空间丢失原因,就进行一些处理,导致直接恢复删除文件并没有修复问题。而对hbase一些命令的底层运行原理不了解,也造成一些操作上的误判。好在这只是测试环境,数据丢失影响不大,接下来需要深入研究hbase各方面的运行机制,避免这种低级问题的发生。

 

posted @ 2020-07-07 15:05  AllEmpty  阅读(2058)  评论(0编辑  收藏  举报