HDFS NameNode fsimage文件corrupt了,怎么办

三世轮回 提交于 2020-12-21 19:22:04

前言


在如今很多用户使用HDFS做为大数据的底层存储时,我们除了关心HDFS的处理性能外,我们经常还需要关注其中数据高可用的情况,例如不能出现数据损坏的情况,比如missing block,或者文件block corrupt的情况。但是其中我们忽略掉了一种最为极端同时也是最为棘手的情况:HDFS NameNode fsimage文件坏了,我们怎么办?元数据的损坏比实际数据损坏可是要严重地多得多。在HDFS中,NN fsimage损坏直接会导致NN启动不起来。目前NN fsimage文件损坏的情况只在极端个别操作行为下产生,所以大部分的使用场景是不会导致fsimage corrupt的情况。但是这不意味着这种极端情况发生的可能性。作为HDFS的集群维护者来说,我们有必要了解以及对此情况的解决方案。本文笔者来分享分享这块的一些经验心得。

NameNode fsimage corrupt场景


首先,本文所说的fsimage的corrupt原因不是说是物理硬件层面造成的fsimage损坏,而是HDFS内部自身程序运行所产生的corrupt的fsimage。你可以简单理解为NN因为内部元数据的损坏,导致checkpoint出了一个corrupt的fsimage文件。归结源头来说还是NN自身进行请求操作处理时,对内存里的元数据更新的错误处理。

上面小节已经提到,目前NN fsimage损坏的情况在绝大部分读写操作中不会触发到,只在极个别情况下的case。这里面的case主要集中在用户启用了HDFS snapshot功能下的情况,其中概括起来目前有3类(据笔者的目前接触了解的情况):

  • 目录里的子文件列表里包含了系统内不存在的文件的情况
  • INode引用指向了一个不存在的INode对象
  • 重复的snapshot deleted diff列表

这3类情况可详见社区JIRA:HDFS-13314和HDFS-13813。在了解完HDFS NN fsimage文件发生corrupt的场景后,下面我们来正式聊聊NN fsimage corrupt的解决办法。

NameNode fsimage corrupt解决办法


NN fsimage文件发生corrupt后,我们有两个解决的思路:

1)第一种,直接修复当前损坏的fsimage文件。
2)第二种,寻找到损坏fsimage文件之前的一个好的fsimage文件+对应的editlog,然后进行NN重启,随后在内存里进行修复。

这里我们详细来聊聊上面提到的两个方案。

方案一,直接修复损坏的fsimage文件。这个方案看似十分的直接,但是倘若我们想做到完美精准地修复,其实并不容易。

比如说我们遇到了目录内包含系统内non-exist文件的情况,这个时候NN在启动load目录信息的时候会报如下的NPE错误。

2020-12-19 22:09:05,282 INFO  namenode.FSImage (FSImage.java:loadFSImageFile(731)) - Planning to load image: FSImageFile(file=/xxx/fsimage_0000000000000000024, cpktTxId=0000000000000000024)
2020-12-19 22:09:05,283 INFO  namenode.FSImageFormatPBINode (FSImageFormatPBINode.java:loadINodeSection(257)) - Loading 6 INodes.
2020-12-19 22:09:05,283 ERROR namenode.FSImage (FSImage.java:loadFSImage(679)) - Failed to load image from FSImageFile(file=/xxx/fsimage_0000000000000000024, cpktTxId=0000000000000000024)
java.lang.NullPointerException
  at org.apache.hadoop.hdfs.server.namenode.INodeDirectory.addChild(INodeDirectory.java:550)
  at org.apache.hadoop.hdfs.server.namenode.FSImageFormatPBINode$Loader.addToParent(FSImageFormatPBINode.java:303)
  at org.apache.hadoop.hdfs.server.namenode.FSImageFormatPBINode$Loader.loadINodeDirectorySection(FSImageFormatPBINode.java:245)
  at org.apache.hadoop.hdfs.server.namenode.FSImageFormatProtobuf$Loader.loadInternal(FSImageFormatProtobuf.java:263)
  at org.apache.hadoop.hdfs.server.namenode.FSImageFormatProtobuf$Loader.load(FSImageFormatProtobuf.java:182)
  at org.apache.hadoop.hdfs.server.namenode.FSImageFormat$LoaderDelegator.load(FSImageFormat.java:226)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:884)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:868)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImageFile(FSImage.java:741)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:672)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:289)
  at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.loadFSImage(FSNamesystem.java:1152)
  at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.loadFromDisk(FSNamesystem.java:761)
  at org.apache.hadoop.hdfs.server.namenode.NameNode.loadNamesystem(NameNode.java:722)
  at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:786)
  at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:1026)
  at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:1010)

这个时候如果简单的去catch这个NPE异常,并非是绝对准确的方式。因为这里面如果还涉及到snapshot的引用持有,在别的地方还是有可能抛出异常的。因此这里并不建议直接去catch load fsimage时发生的异常来进行修复的办法。

接着我们来看方案二,通过一个好的fsimage+editlog的方式进行恢复。这个方案的一个优势在于它至少能够让NN正常启动起来了。但是等NN启动完毕,加载掉后续的editlog后,它此时内存的状态还是corrupt的,它又会checkpoint出一个坏的fsimage文件。

这个时候呢,我们就要想办法去修复掉那些“坏掉”的元数据信息,一种方式就是找到它们并且删除掉它们。目前社区有对这块的改进,可以帮助我们检测并打印出这些corrupt文件目录的信息,相关JIRA也同样是上面提到的HDFS-13314和HDFS-13813两个JIRA。

笔者将上述JIRA patch改进apply后,同样执行NN fsimage corrupt的场景后,此时从NN log里能够找到corrupt相关的文件信息了,如下:

2020-12-19 22:27:21,831 INFO  namenode.FileJournalManager (FileJournalManager.java:finalizeLogSegment(142)) - Finalizing edits file /xxx/edits_inprogress_0000000000000000001 -> /xxx/edits_0000000000000000001-0000000000000000024
2020-12-19 22:27:21,832 INFO  namenode.FSImageFormatProtobuf (FSImageFormatProtobuf.java:save(417)) - Saving image file /xxx/fsimage.ckpt_0000000000000000024 using no compression
2020-12-19 22:27:21,832 INFO  namenode.FSImageFormatProtobuf (FSImageFormatProtobuf.java:save(417)) - Saving image file /xxx/fsimage.ckpt_0000000000000000024 using no compression
2020-12-19 22:27:21,838 ERROR namenode.FSImage (FSImageFormatPBINode.java:serializeINodeDirectorySection(556)) - FSImageFormatPBINode#serializeINodeDirectorySection: Dangling child pointer found. Missing INode in inodeMap: id=16391; parent dir path=dirb; path=file1; parent=null
2020-12-19 22:27:21,838 ERROR namenode.FSImage (FSImageFormatPBINode.java:serializeINodeDirectorySection(556)) - FSImageFormatPBINode#serializeINodeDirectorySection: Dangling child pointer found. Missing INode in inodeMap: id=16391; parent dir path=dirb; path=file1; parent=null
2020-12-19 22:27:21,861 INFO  namenode.FSImageFormatProtobuf (FSImageFormatProtobuf.java:save(421)) - Image file /xxx/fsimage.ckpt_0000000000000000024 of size 963 bytes saved in 0 seconds  with 1 errors.
2020-12-19 22:27:21,861 ERROR namenode.FSImage (FSImage.java:saveFSImage(931)) - Detected 1 errors while saving FsImage /xxx/fsimage_0000000000000000024
2020-12-19 22:27:21,861 INFO  namenode.FSImageFormatProtobuf (FSImageFormatProtobuf.java:save(421)) - Image file /xxx/fsimage.ckpt_0000000000000000024 of size 963 bytes saved in 0 seconds  with 1 errors.
2020-12-19 22:27:21,861 ERROR namenode.FSImage (FSImage.java:saveFSImage(931)) - Detected 1 errors while saving FsImage /xxx/fsimage_0000000000000000024
2020-12-19 22:27:21,863 INFO  namenode.FSEditLog (FSEditLog.java:startLogSegment(1299)) - Starting log segment at 25
2020-12-19 22:27:21,866 FATAL namenode.FSImage (FSImage.java:saveNamespace(1074)) - NameNode process will exit now... The saved FsImage IMAGE is potentially corrupted.
2020-12-19 22:27:21,866 INFO  util.ExitUtil (ExitUtil.java:terminate(124)) - Exiting with status -1
2020-12-19 22:27:21,866 FATAL util.ExitUtil (ExitUtil.java:terminate(127)) - Terminate called
org.apache.hadoop.util.ExitUtil$ExitException: ExitException
  at org.apache.hadoop.util.ExitUtil.terminate(ExitUtil.java:126)
  at org.apache.hadoop.util.ExitUtil.terminate(ExitUtil.java:192)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.saveNamespace(FSImage.java:1076)
  at org.apache.hadoop.hdfs.server.namenode.FSImage.saveNamespace(FSImage.java:1028)
  at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.saveNamespace(FSNamesystem.java:5490)
  at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.saveNamespace(NameNodeRpcServer.java:1220)
  at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.saveNamespace(ClientNamenodeProtocolServerSideTranslatorPB.java:774)
  at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
  at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:639)
  at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:982)
  at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2412)
  at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2408)
  at java.security.AccessController.doPrivileged(Native Method)
  at javax.security.auth.Subject.doAs(Subject.java:422)
  at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1869)
  at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2408)
2020-12-19 22:27:21,871 INFO  hdfs.MiniDFSCluster (MiniDFSCluster.java:shutdown(1791)) - Shutting down the Mini HDFS Cluster

上述的改动源自HDFS-13314,它让NN在每次checkpoint时进行INode信息的corrupt检查,如果发现有损坏的情况,则将这些信息打印出来,同时shutdown当前的NN,以此让管理员人工介入检查。上面显示的这行即是corrupt的信息:

2020-12-19 22:27:21,838 ERROR namenode.FSImage (FSImageFormatPBINode.java:serializeINodeDirectorySection(556)) - FSImageFormatPBINode#serializeINodeDirectorySection: Dangling child pointer found. Missing INode in inodeMap: id=16391; parent dir path=dirb; path=file1; parent=null

OK,在我们了解了那些损坏了的元数据信息后,我们可以在启动后的NN里进行对应数据的删除操作。删除好后,我们再观察checkpoint新fsimage后,还是否有上述corrupt信息的出现。在笔者的测试case里,删除掉损坏文件信息的方法是能够修复的。当然还有另外一种办法进行corrupt的信息的移除,通过hard-code部分corrupt path来skip这些元数据信息的load。这个办法也是社区JIRA里提到的一种修复办法。

在这里最坏的一种情况是,我们找到了这些corrupt的元数据信息,但是我们没办法从NN内存里移除掉。这个时候,我们就不得不作出部分数据丢失的一种修复办法;

1)找到发生corrupt行为对应的editlog文件位置
2)移除掉1)步骤中的editlog及之后的所有editlog
3)进行好的fsimage以及剩余editlog的加载

上面NN启动过程就能确保NN启动完毕是一个正确的元数据状态了,但是它会丢失一部分transaction的更新,对应的用户影响即最近数据的更新写入都将丢失。当然,这种有损恢复的方式只是在迫不得已的情况下使用而已,正常情况还是应尽可能地通过上面提到的方案二的方式来做比较好。

NN fsimage corrupt的重新行为


这里笔者提供一个社区发现的一个能够造成fsimage corrupt的重新操作,(仅供测试使用!!!)

/apache/hadoop/bin/hadoop fs -mkdir -p /dir1/dira/dirb
/apache/hadoop/bin/hadoop fs -mkdir -p /dir1/dirx
/apache/hadoop/bin/hadoop fs -mkdir -p /dir2

/apache/hadoop/bin/hdfs  dfsadmin -allowSnapshot /dir1
/apache/hadoop/bin/hdfs dfs -createSnapshot /dir1 s0
/apache/hadoop/bin/hadoop fs -put hdfs-site.xml /dir1/dira/dirb/
/apache/hadoop/bin/hadoop fs -mv /dir1/dira/dirb /dir1/dirx/dirb

/apache/hadoop/bin/hdfs dfs -createSnapshot /dir1 s1
/apache/hadoop/bin/hadoop fs -appendToFile hdfs-site.xml /dir1/dirx/dirb/hdfs-site.xml
/apache/hadoop/bin/hadoop fs -mkdir /dir2/dira
/apache/hadoop/bin/hadoop fs -mv /dir1/dirx/dirb /dir2/dira/dirb

/apache/hadoop/bin/hadoop fs -rm -r /dir2/dira/dirb
/apache/hadoop/bin/hadoop fs -rm -r /user/hdfs/.Trash/Current
/apache/hadoop/bin/hdfs dfs -deleteSnapshot /dir1 s1

这个corrupt的case fix起来很简单,拿之前好的fsimage文件,load启动成功后,执行删除snapshot s0的操作即可:

/apache/hadoop/bin/hdfs dfs -deleteSnapshot /dir1 s0

有的时候我们为了测试的方便,可以拿fsimage文件直接在一个测试的节点启动进行测试,无须任何的JN,DN节点,笔者的测试做法如下:

1)启动时将NN HA2个地址中的另外一个随便写出一个假的地址,防止NN启动解析保错。
2)测试NN启动好后,将上面HA NN地址都写出本地地址,避免hdfs命令执行发现不存在的NN导致执行失败。

以上就是本文所要阐述的关于HDFS NN fsimage corrupt恢复的相关内容了,在参考链接里笔者还附带上了几个关于fsimage corrupt相关的JIRA链接,感兴趣的同学可继续深入了解。

参考链接


[1].https://issues.apache.org/jira/browse/HDFS-9406
[2].https://issues.apache.org/jira/browse/HDFS-13314
[3].https://issues.apache.org/jira/browse/HDFS-13813
[4].https://issues.apache.org/jira/browse/HDFS-13101
[5].https://issues.apache.org/jira/browse/HDFS-15313
[6].https://issues.apache.org/jira/browse/HDFS-15012




标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!