HDFS NameNode fsimage文件corrupt了,怎麼辦

前言


在如今很多用戶使用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




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章