FSImage文件是HDFS中名字节点NameNode上文件/目录元数据在特定某一时刻的持久化存储文件。它的作用不言而喻,在HA出现之前,NameNode因为各种原因宕机后,若要恢复或在其他机器上重启NameNode,重新组织元数据,就需要加载对应的FSImage文件、FSEditLog文件,并在内存中重做FSEditLog文件中的事务条目。本节,我们先来看下FSImage文件格式,及其内部数据是如何组织的。
通过翻看HDFS中加载FSImage文件的代码,从FSNamesystem的loadFSImage()方法开始,我将HDFS集群上的一个FSImage文件放到本地Windows系统中的F盘下,并写了如下方法解析文件,并打印关键内容,如下:
import java.io.IOException;
import java.io.File;
import java.util.List;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.RandomAccessFile;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary;
import org.apache.hadoop.hdfs.server.namenode.FsImageProto.FileSummary.Section;
public class TestImageUtil {
@Test
public void testImage() {
// 文件头字符串HDFSIMG1对应byte[]
byte[] fileHead = "HDFSIMG1".getBytes();
RandomAccessFile raFile = null;
try {
// 创建文件file,对应为f盘下FSImage文件fsimage_0000000000002311798
File file = new File("f:/fsimage_0000000000002311798");
raFile = new RandomAccessFile(file, "r");
// 文件summary长度域所占大小为4
final int FILE_LENGTH_FIELD_SIZE = 4;
System.out.println("文件summary长度域大小:FILE_LENGTH_FIELD_SIZE=" + FILE_LENGTH_FIELD_SIZE);
// 获取FSImage文件长度
long fileLength = raFile.length();
System.out.println("获取FSImage文件长度:fileLength=" + fileLength);
// 创建文件头byte[]数组fileHeadTmp,用于存储文件头byte[]数组,大小为上述fileHead数组大小
byte[] fileHeadTmp = new byte[fileHead.length];
// 读入文件头至byte[]数组fileHeadTmp
System.out.println("文件从头开始读取" + fileHeadTmp.length + "个byte至byte[]数组fileHeadTmp");
raFile.readFully(fileHeadTmp);
// 获取文件头长度
System.out.println("获取文件头长度:fileHeadLength=" + fileHead.length);
// 将byte[]数组fileHeadTmp转换成字符串fileHeadString
String fileHeadString = new String(fileHeadTmp);
// 验证文件头字符串
System.out.println("fileHeadString