![](https://img.haomeiwen.com/i15041653/f367acaf31c78ca0.png)
FSNamesystem.java
void startCommonServices(Configuration conf, HAContext haContext) throws IOException {
this.registerMBean(); // register the MBean for the FSNamesystemState
writeLock();
this.haContext = haContext;
try {
/**
* hadoop namenode -> fsimage + editLog(磁盘) -> 存储资源是否够?100m
*/
//NameNode资源检查 通过core-site.xml hdfs-site.xml两个文件,就知道了元数据存在哪儿?
//(1)NameNode的两个目录:存储fsiamge的目录,存储editlog的目录。
// 但是一般情况下,或者默认情况这两个使用的是同一个目录。
//加载了配置文件,配置文件里面有存储元数据的目录。
nnResourceChecker = new NameNodeResourceChecker(conf);
//TODO 检查是否有足够的磁盘存储元数据
checkAvailableResources();
assert safeMode != null && !isPopulatingReplQueues();
StartupProgress prog = NameNode.getStartupProgress();
prog.beginPhase(Phase.SAFEMODE);
prog.setTotal(Phase.SAFEMODE, STEP_AWAITING_REPORTED_BLOCKS,
getCompleteBlocksTotal());
//TODO HDFS的安全模式
setBlockTotal();
//TODO 启动重要服务
blockManager.activate(conf);
} finally {
writeUnlock();
}
registerMXBean();
DefaultMetricsSystem.instance().register(this);
if (inodeAttributeProvider != null) {
inodeAttributeProvider.start();
dir.setINodeAttributeProvider(inodeAttributeProvider);
}
snapshotManager.registerMXBean();
}
public void setBlockTotal() {
// safeMode is volatile, and may be set to null at any time
SafeModeInfo safeMode = this.safeMode;
if (safeMode == null)
return;
//TODO 设置安全模式
//getCompleteBlocksTotal()集群里面应该能正常使用的block的个数
safeMode.setBlockTotal((int)getCompleteBlocksTotal());
}
/**
* Get the total number of COMPLETE blocks in the system.
* For safe mode only complete blocks are counted
* TODO 在HDFS集群里面block的状态分为两种类型:
* 1)complete类型:正常的可用的block。
* 2)underconstuction类型:处于正在构建的block
* 返回去的就是历史所有已经complete状态的block的个数
*/
private long getCompleteBlocksTotal() {
// Calculate number of blocks under construction
long numUCBlocks = 0;
readLock();
//获取所有正在构建的block
numUCBlocks = leaseManager.getNumUnderConstructionBlocks();
try { //获取所有的block - 正在构建的block = 应该能正常使用的总的block
return getBlocksTotal() - numUCBlocks;
} finally {
readUnlock();
}
}
/**
* Set total number of blocks.
*
* total:complete状态的block的个数,也就是我们正常的block的个数
*
* 1000 block 999 处于安全模式
*
*/
private synchronized void setBlockTotal(int total) {//1000 block
this.blockTotal = total;
//TODO 计算阈值
//1000 * 0.999 = 999
this.blockThreshold = (int) (blockTotal * threshold);
//999
this.blockReplQueueThreshold =
(int) (blockTotal * replQueueThreshold);
if (haEnabled) {
// After we initialize the block count, any further namespace
// modifications done while in safe mode need to keep track
// of the number of total blocks in the system.
this.shouldIncrementallyTrackBlocks = true;
}
if(blockSafe < 0)
this.blockSafe = 0;
//TODO 检查安全模式
checkMode();
}
/**
* There is no need to enter safe mode
* if DFS is empty or {@link #threshold} == 0
*
* TODO 条件一
* threshold != 0 && blockSafe < blockThreshold
* HDFS的元数据那儿程序总计分析出来上一次关闭集群之前
* 假设有1000个complete的block,默认是阈值的计算比例是0.999
* 这样blockThreshold的值是999
* 现在集群起来了以后,发现累计datanode汇报过来的complete的block个数(blockSafe)
* 如果小于999就让集群处于安全模式。
*
* TODO 条件二
* datanodeThreshold != 0 && getNumLiveDataNodes() < datanodeThreshold
* 如果存活的datanode的个数小于一定的数目的时候,也会进去安全模式
* 默认是0,所以相当于没启用,但是我们也可以配置,如果存活的datanode个数
* 少于多少就让HDFS集群出入安全模式。
* TODO 条件三
* !nameNodeHasResourcesAvailable()
* 就是前面 检查NameNode写的元数据的目录空间是否大于100M,
* 如果目录的空间小于100M,nameNodeHasResourcesAvailable 就为false
* hdfs就会进入安全模式。
*/
private boolean needEnter() {
//999
return (threshold != 0 && blockSafe < blockThreshold) ||
//默认这条件是不生效的
//100个节点,99
(datanodeThreshold != 0 && getNumLiveDataNodes() < datanodeThreshold) ||
//!false
(!nameNodeHasResourcesAvailable());
}
/**
* Increment number of safe blocks if current block has
* reached minimal replication.
* @param replication current replication
*/
private synchronized void incrementSafeBlockCount(short replication) {
if (replication == safeReplication) {
//datanode会进行block的汇报 block信息 -> namenode
//1000
this.blockSafe++; //累计我们datanode汇报过来完整的block块
// Report startup progress only if we haven't completed startup yet.
StartupProgress prog = NameNode.getStartupProgress();
if (prog.getStatus(Phase.SAFEMODE) != Status.COMPLETE) {
if (this.awaitingReportedBlocksCounter == null) {
this.awaitingReportedBlocksCounter = prog.getCounter(Phase.SAFEMODE,
STEP_AWAITING_REPORTED_BLOCKS);
}
this.awaitingReportedBlocksCounter.increment();
}
checkMode();
}
}
总结
blockTotal=hdfs总块数
this.blockThreshold = (int) (blockTotal * threshold);
threshold=0.999
blockThreshold = 999
也就是只允许hdfs丢失一个块
条件
1、datanode上报的块个数少于blockTh reshold=0.999*total synchronized incrementSafeBlockCount()方法中 this.blockSafe++;
2、集群活跃节点少于 datanodethead 比如30个节点,挂了一个,直接进入安全模式,一般不使用,默认datanodethead=0
3、判断磁盘空间是否namenode写元数据的磁盘空间是否大于100m,如果小于就进入安全模式
一般是进入安全模式,就是数据块丢失了
注意:namenode-设置的datanode心跳超时时间是10min30s,为什么?
容错,场景是在datanode的副本补齐操作,占用大量网络带宽
4、元数据文件内容
fsimage文件内容
<INodeDirectorySection>
<directory>
<parent>16385</parent>
<inode>18543</inode>
<inode>16474</inode>
<inode>16419</inode>
<inode>16417</inode>
<inode>16427</inode>
<inode>17544</inode>
<inode>17561</inode>
</directory>
<directory>
<parent>16417</parent>
<inode>16420</inode>
</directory>
<directory>
<parent>16419</parent>
<inode>17399</inode>
<inode>17258</inode>
<inode>16418</inode>
<inode>17294</inode>
</directory>
...... // 省略其他<directory>标签
</INodeDirectorySection>
网友评论