【大数据系列】HDFS安全模式

一、什么是安全模式

安全模式时HDFS所处的一种特殊状态,在这种状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。在NameNode主节点启动时,HDFS首先进入安全模式,DataNode在启动的时候会向namenode汇报可用的block等状态,当整个系统达到安全标准时,HDFS自动离开安全模式。如果HDFS处于安全模式下,则文件block不能进行任何的副本复制操作,因此达到最小的副本数量要求是基于datanode启动时的状态来判定的,启动时不会再做任何复制。

二、安全模式的相关配置

系统离开安全模式的条件:

1)可用的block占总数的比例

2)可用的数据节点数量符合要求

三、配置  hdfs-site.xml

dfs.namenode.replication.min:最小的文件block副本数量,默认为1

dfs.namenode.safemode.threshold-pct:副本数达到最小要求的block占系统总block数的百分比,当实际比例超出该配置后,才能离开安全模式

dfs.namenode.safemode.min.datanodes:离开安全模式的最小可用(alive)datanode数量要求,默认是0,也就是即使所有datanode都不可用,仍然可以离开安全模式

dfs.namenode.safemode.extension:当集群可用block比例,可用datanode都达到要求之后,如果在extension配置额时间段之后依然能满足要求,此时集群才离开安全模式,单位为毫秒。默认为1,也就是当满足条件并且能够维持1毫秒之后,离开安全模式。这个配置主要是针对集群的稳定程度做进一步的确认

四、相关操作命令

hadoop dfsadmin -safemode <command>

  • get     查看当前状态
  • enter   进入安全模式
  • leave   强制离开安全模式
  • wait   一直等待直到安全模式结束

 五、源码分析

import org.apache.hadoop.classification.InterfaceAudience.Private;
import org.apache.hadoop.hdfs.protocol.Block;

@Private
public interface SafeMode {
    //检查进入或者退出安全模式的条件是否满足,如果满足,进入或退出安全模式
    void checkSafeMode();
    //系统当前是否处于安全模式
    boolean isInSafeMode();
    //系统启动时是否自动进入安全模式
    boolean isInStartupSafeMode();
   
    boolean isPopulatingReplQueues();
    //增加达到最小副本数要求的block数
    void incrementSafeBlockCount(int var1);
    //降低达到最小副本数要求的block数
    void decrementSafeBlockCount(Block var1);
}


//周期性的检测是否可以离开安全模式,逻辑封装在run方法中
class SafeModeMonitor implements Runnable {
        //两次检测间隔的毫秒数,即1秒
        private static final long recheckInterval = 1000L;

        SafeModeMonitor() {
        }

        public void run() {
            //系统运行时,循环检测
            while(FSNamesystem.this.fsRunning) {
                FSNamesystem.this.writeLock();

                try {
                    //没有安全模式相关信息,也就是不在安全模式
                    if(FSNamesystem.this.safeMode == null) {
                       //线程退出
                        break;
                    }

                    if(FSNamesystem.this.safeMode.canLeave()) {
                        //离开安全模式
                        FSNamesystem.this.safeMode.leave();
                        FSNamesystem.this.smmthread = null;
                        //离开安全模式之后,线程退出
                        break;
                    }
                } finally {
                    FSNamesystem.this.writeUnlock();
                }

                try {
                    //两次检测之间,线程休眠
                    Thread.sleep(1000L);
                } catch (InterruptedException var4) {
                    ;
                }
            }
            //当系统不在运行的时候,线程结束退出
            if(!FSNamesystem.this.fsRunning) {
                FSNamesystem.LOG.info("NameNode is being shutdown, exit SafeModeMonitor thread");
            }

        }
    }

  

在FSNamesystem.class中有SafeModeInfo用于保存安全模式下的相关信息:private volatile FSNamesystem.SafeModeInfo safeMode;
这个变量的类型为volatile,也就是桌该线程对该变量的任何修改完成后,其他线程立刻可以看到变化

 

private SafeModeInfo(Configuration conf) {
            this.reached = -1L;
            this.reachedTimestamp = -1L;
            this.lastStatusReport = 0L;
            this.resourcesLow = false;
            this.shouldIncrementallyTrackBlocks = false;
            //这个就是之前提到过的百分比配置
            this.threshold = (double)conf.getFloat("dfs.namenode.safemode.threshold-pct", 0.999F);
            if(this.threshold > 1.0D) {
                FSNamesystem.LOG.warn("The threshold value should\'t be greater than 1, threshold: " + this.threshold);
            }
            //最小可用的datanode数量配置
            this.datanodeThreshold = conf.getInt("dfs.namenode.safemode.min.datanodes", 0);
            this.extension = conf.getInt("dfs.namenode.safemode.extension", 0);
            this.safeReplication = conf.getInt("dfs.namenode.replication.min", 1);
            FSNamesystem.LOG.info("dfs.namenode.safemode.threshold-pct = " + this.threshold);
            FSNamesystem.LOG.info("dfs.namenode.safemode.min.datanodes = " + this.datanodeThreshold);
            FSNamesystem.LOG.info("dfs.namenode.safemode.extension     = " + this.extension);
            this.replQueueThreshold = (double)conf.getFloat("dfs.namenode.replqueue.threshold-pct", (float)this.threshold);
            this.blockTotal = 0;
            this.blockSafe = 0;
        }

  即:SafeModeMonitor作为守护线程,在收到来自datanode的BlockReport状态报告之后,周期性检测是否达到离开安全模式的条件,如果符合,则离开安全模式。        

posted @ 2017-12-13 14:15  霓裳梦竹  阅读(994)  评论(0编辑  收藏  举报