HBase的存储完全建立在HDFS之上,一旦HDFS的数据块出现损坏,HBase的表现往往非常诡异:有的region无法打开,有的Scan操作中途抛出IOException,Master日志里则反复出现BlockMissingException或者UnderReplicatedBlocks的告警。遇到这类问题不要慌,HDFS本身有多副本机制,单副本损坏大多数情况下都能自动恢复,真正麻烦的是所有副本同时损坏。下面按照实际的排查修复流程,把整个过程拆开讲清楚。

一、如何确认HDFS块真的损坏了
排查的第一步是跑一遍文件系统检查。HDFS提供了fsck工具,可以扫描整个命名空间并报告缺失或损坏的块。执行下面的命令:
hdfs fsck / -list-corruptfileblocks hdfs fsck /hbase -files -blocks -locations | grep -i corrupt
第一条命令会直接列出所有处于损坏状态的文件路径,第二条则针对HBase的根目录做详细检查,输出每个文件对应的块信息以及块所在的DataNode位置。如果输出中出现了CORRUPT字样,就说明该块的所有副本都无法读取,属于完全损坏;如果只是UNDER REPLICATED,说明副本数不足但仍有存活副本,这种情况HDFS会自动补齐,一般不需要人工干预。
除了fsck,还要注意核对几个容易混淆的现象。比如DataNode磁盘满了会导致块暂时不可读,网络抖动会造成短时间的块访问失败,这些都不算真正的损坏。可以先用hdfs dfsadmin -report看一眼各DataNode的容量和存活状态,排除掉基础设施层面的问题,再下结论。另外,HBase侧的日志也要同步查看,如果RegionServer日志中出现Can't get locations for the chunk这类错误,结合fsck的结果基本就能锁定问题文件了。
二、损坏块的三种修复方案与适用场景
确认损坏之后,根据数据的重要程度和损坏范围,选择不同的修复路径。这里给出三种常见方案,各自适用的情况差别很大。
1. 删除损坏文件让HBase自动重建
如果损坏的是WAL(Write-Ahead Log)文件或者已经过期的HFile,最简单的办法是直接删除损坏文件,让HBase自己恢复。操作步骤如下:
# 先删除HDFS上的损坏文件 hdfs dfs -rm /hbase/WALs/host-1.example,16000,1680000000000/xxx.inprogress # 如果文件在回收站,彻底清掉 hdfs dfs -rm -skipTrash /hbase/WALs/host-1.example,16000,1680000000000/xxx.inprogress # 重启RegionServer让它重新上线region hbase-daemon.sh stop regionserver hbase-daemon.sh start regionserver
这种方式的代价最小,但前提是你能判断这个文件确实可以丢弃。WAL文件在数据已经flush到HFile之后就没有价值了,删掉不影响数据;但如果损坏的HFile里还有未合并的业务数据,删除就意味着这部分数据永久丢失,需要提前和业务方确认。
2. 利用副本机制抢救数据
当fsck显示块处于misreplicated或者部分副本损坏时,可以尝试让HDFS重新平衡副本。先执行:
# 检查并尝试自动修复副本布局 hdfs fsck /hbase -repair -replicate # 触发块汇报,让NameNode尽快感知存活的副本 hdfs dfsadmin -triggerBlockReport
-repair参数会尝试重新调度复制任务,把还活着的副本复制到其他DataNode上,等副本数达标后块的读取就恢复正常了。这种方式适合磁盘出现坏道但集群整体健康的情况,修复过程对HBase透明,不需要停表。
3. 从备份或快照恢复
如果所有副本全部损坏,HDFS层面已经无能为力,只能依赖备份。前提是你提前开启了HBase快照或者做了定期导出:
# 基于快照恢复一张表 hbase shell > disable 'user_table' > restore_snapshot 'user_table_snapshot_20240101' > enable 'user_table' # 或者克隆快照到一张新表进行验证 > clone_snapshot 'user_table_snapshot_20240101', 'user_table_restore'
快照恢复的前提是快照文件所在的HDFS块本身没有损坏,所以生产环境建议把关键表的快照定期 DistCP 到异地集群,形成真正的异地容灾。如果没有快照也没有备份,剩下的办法就只有从数据源头重新灌入了。
三、修复后的校验与预防措施
修复完成不等于万事大吉,必须做一轮完整校验。先再跑一次hdfs fsck /hbase,确认输出中没有corrupt状态;然后在HBase shell里用status 'detailed'查看是否有region长期处于FAILED_OPEN状态;最后对恢复的表做抽样Scan,重点检查损坏时间点附近的数据是否符合预期。如果发现表元数据不一致,可以再用hbase hbck -repair做一次修复,不过hbck在HBase 2.x之后的版本能力有所收缩,部分功能需要改用hbck2配合HBase的HBCK2工具完成,使用前务必核对自己集群的版本。
预防层面,有几件事值得长期坚持。第一,保持dfs.replication至少为3,重要集群可以配机架感知策略,避免同一机架断电导致副本全灭;第二,开启dfs.datanode.scan.period.hours让DataNode定期做块校验,发现校验和不匹配时提前触发重新复制;第三,建立定期快照加异地备份的机制,这是最后一道防线;第四,监控上要对UnderReplicatedBlocks和MissingBlocks指标配置告警,很多块损坏事故其实在恶化前就有信号,只是没人盯着而已。
总结一下,HDFS块损坏的处理核心是先定位、再判断损坏范围、最后按数据价值选择修复路径。多数情况下副本机制能自救,真正需要人工介入的是全副本损坏场景,而那个场景的答案只有备份。把日常巡检和快照策略做扎实,比事后任何修复手段都更省心。