前言
对于大部分使用HDFS作为大数据存储系统的用户而言,NameNode的启动过程缓慢已经可以算是一个十分痛点的问题。尤其是当NN的元数据规模达到数亿万级别时,这个过程总的耗时时间将会达到几小时的级别。这意味着什么呢?这意味着假设当系统因为异常退出时,再次恢复服务需要至少等超过1个小时以上。最近社区完成了一个重要的改进,benchmark结果显示可以让NN加载时间提速将近1倍,本文笔者来聊聊这个重要的改动,相信对于HDFS开发者来说绝对是个意义重大的改进。
HDFS NN的启动过程
在介绍正文之前,先来说说NN的启动加载过程,我们总是说NN启动好慢,那么它到底是慢在什么阶段呢?如果我们想做里面的启动加速,我们首先要知道问题的点在于哪里。
NN的启动过程里面包含了如下几个阶段(从先往后的顺序):
- 1)INode数据的加载
- 2)Editlog的apply
- 3)等待DN的block report,达到block report阈值后,退出Safe Mode模式
在以上3个子过程中,耗时时间排序依次为1)>3)>2)(这里假设是亿万INode规模下),其中1)过程的耗时远远超出2), 3)的执行耗时,可以说这里面主要耗时的过程要属于INode数据的加载了。INode数据的加载耗时最长其实也不难理解,因为这里会有大量的INode对象的解析行为,更为关键的一点是这个过程是单步串行操作的。那么假设我们可以让这个过程从串行的方式变为多步并行的方式,那么是否可以极大地提高NN的启动过程呢?
目前NN串行加载的方式本质上来说是由于其FSImage文件的内部结构所决定的。FSImage内部通过以不同的Section段作为划分,逐段写入每类Section的对象数据。从先往后以此写入INode数据,最后再写入Section的索引,相关控制代码如下:
...
step = new Step(StepType.INODES, filePath);
prog.beginStep(Phase.SAVING_CHECKPOINT, step);
// Count number of non-fatal errors when saving inodes and snapshots.
long numErrors = saveInodes(b);
numErrors += saveSnapshots(b);
prog.endStep(Phase.SAVING_CHECKPOINT, step);
step = new Step(StepType.DELEGATION_TOKENS, filePath);
prog.beginStep(Phase.SAVING_CHECKPOINT, step);
saveSecretManagerSection(b);
prog.endStep(Phase.SAVING_CHECKPOINT, step);
...
private long saveInodes(FileSummary.Builder summary) throws IOException {
FSImageFormatPBINode.Saver saver = new FSImageFormatPBINode.Saver(this,
summary);
// 按照顺序进行Section的写出
saver.serializeINodeSection(sectionOutputStream);
saver.serializeINodeDirectorySection(sectionOutputStream);
saver.serializeFilesUCSection(sectionOutputStream);
return saver.getNumImageErrors();