FSImage并行加载
关于NameNode FSImage并行加载现在有很多文章都详细介绍过,比如:https://blog.csdn.net/Androidlushangderen/article/details/100088073,所以这里就不大篇幅说了
简单总结就是开启该功能后,FSImage文件里的FILESUMMARY将会添加INODE_SUB和INODE_DIR_SUB两类SECTION的索引,将INODE和INODE_DIR两个Section进行逻辑拆分,以实现并行加载。
并行加载FSImage可以显著提高NameNode重启效率,issue链接:https://issues.apache.org/jira/browse/HDFS-14617
OIV简介
Offline Image Viewer 是将 hdfs fsimage 文件的内容转储为人类可读格式并提供只读 WebHDFS API 的工具,以便允许对 Hadoop 集群的namespace进行离线分析和检查,该工具能够相对快速地处理非常大的image文件。官网地址:https://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html
如果集群开启了FSImage并行加载功能,这里衍生出几个问题:
- oiv 会走这个并行加载逻辑吗? 能不能受益?
- oiv的解析产出的结果会有什么变化?
- 旧版本的oiv能解析并行格式的FSImage吗?
这里提前给出结论
- oiv不走这个加载逻辑,不受益
- oiv的解析产出的结果没有变化
- hadoop3.3.0以下版本的oiv无法解析并行格式的FSImage,需要升级到hadoop3.3.0版本,或backport HDFS-14617
相关代码
一、NameNode启动时加载FSImage的逻辑
org.apache.hadoop.hdfs.server.namenode.FSImageFormatProtobuf.java
private void loadInternal(RandomAccessFile raFile, FileInputStream fin)
throws IOException {
if (!FSImageUtil.checkFileFormat(raFile)) {
throw new IOException("Unrecognized file format");
}
FileSummary summary = FSImageUtil.loadSummary(raFile);
if (requireSameLayoutVersion && summary.getLayoutVersion() !=
HdfsServerConstants.NAMENODE_LAYOUT_VERSION) {
throw new IOException("Image version " + summary.getLayoutVersion() +
" is not equal to the software version " +
HdfsServerConstants.NAMENODE_LAYOUT_VERSION);
}
FileChannel channel = fin.getChannel();
FSImageFormatPBINode.Loader inodeLoader = new FSImageFormatPBINode.Loader(
fsn, this);
FSImageFormatPBSnapshot.Loader snapshotLoader = new FSImageFormatPBSnapshot.Loader(
fsn, this);
ArrayList<FileSummary.Section> sections = Lists.newArrayList(summary
.getSectionsList());
Collections.sort(sections, new Comparator<FileSummary.Section>() {
@Override
public int compare(FileSummary.Section s1, FileSummary.Section s2) {
SectionName n1 = SectionName.fromString(s1.getName());
SectionName n2 = SectionName.fromString(s2.getName());
if (n1 == null) {
return n2 == null ? 0 : -1;
} else if (n2 == null) {
return -1;
} else {
return n1.ordinal() - n2.ordinal();
}
}
});
StartupProgress prog = NameNode.getStartupProgress();
/**
* beginStep() and the endStep() calls do not match the boundary of the
* sections. This is because that the current implementation only allows
* a particular step to be started for once.
*/
Step currentStep = null;
boolean loadInParallel = enableParallelSaveAndLoad(conf);
ExecutorService executorService = null