HADOOP NAMENODE FORMAT过程分析

namenode format操作是使用hadoop分布式文件系统前的步骤。如果不执行这个步骤,无法正确启动分布式文件系统。所以个人认为有必要对这个过程进行分析。

(1)启动format

hadoop namenode -format

在之前关于start-dfs.sh的脚本分析过程,已经介绍到hadoop的脚本,namenode对应的执行类是 org.apache.hadoop.hdfs.server.namenode.NameNode类,传入的-format参数传入到执行类,作为执行 类的参数。

(2)NameNode的入口main函数

try {
      StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);
      NameNode namenode = createNameNode(argv, null);
//通过createNameNode方法创建NameNode对象,并传入参数,这里传入的是-format
      if (namenode != null)
        namenode.join();
    } catch (Throwable e) {
      LOG.error(StringUtils.stringifyException(e));
      System.exit(-1);
    }

(3)NameNode.createNameNode创建NameNode实例

if (conf == null)
      conf = new Configuration();
//创建Configuration实例,获取配置参数。
    StartupOption startOpt = parseArguments(argv); //解析参数
    if (startOpt == null) {
      printUsage();
      return null;
    }
    setStartupOption(conf, startOpt);


    switch (startOpt) {
      case FORMAT:    
 //对应-format参数
        boolean aborted = format(conf, true); //执行format()
        System.exit(aborted ? 1 : 0);              //执行后,直接退出,并不启动namenode服务
      case FINALIZE:
        aborted = finalize(conf, true);
        System.exit(aborted ? 1 : 0);
      default:
    }
    DefaultMetricsSystem.initialize("NameNode");    
//如果不是-format和-finalize参数,则创建NameNode实例,启动namenode服务
    NameNode namenode = new NameNode(conf);
    return namenode;

(3)执行NameNode.format格式化hdfs操作

这个过程是整个format的流程的主要部分,里面设计到FSNamesystem和FSImage两个和hdfs文件系统关系密切的类。在这里并不展开说明,仅对其和format相关的操作进行分析

Collection<File> dirsToFormat = FSNamesystem.getNamespaceDirs(conf); //通过配置文件配置参数获取fsimage文件所存放的目录,本文后面的部分会单独介绍fsimage文件
    Collection<File> editDirsToFormat = 
                 FSNamesystem.getNamespaceEditsDirs(conf);                                 
 //通过配置文件配置参数获取edits文件所存放的目录,本文后面的部分会单独介绍edits文件
    //下面的for循环,用于验证fsimage存放的目录,如果已存在,需要用户确认是否要格式化,如果不允许格式化,则退出。

    for(Iterator<File> it = dirsToFormat.iterator(); it.hasNext();) {
      File curDir = it.next();
      if (!curDir.exists())
        continue;
      if (isConfirmationNeeded) {
        System.err.print("Re-format filesystem in " + curDir +" ? (Y or N) ");
        if (!(System.in.read() == 'Y')) {
          System.err.println("Format aborted in "+ curDir);
          return true;
        }
        while(System.in.read() != '\n'); // discard the enter-key
      }
    }


    //这里分两个步骤,一个是new FSImage,一个是new FSNamesystem.

   //new FSImage调用了FSImage的setStorageDirectories方法,将fsimage和edits目录都存放在StorageDirectory列表storageDirs中

   //并且每个StorageDirectory以NameNodeDirType为IMAGE_AND_EDITS、IMAGE、EDITS来区分。

   //new FSNamesystem创建了HDFS文件系统的根目录FSDirectory对象dir和DelegationTokenSecretManager对象dtSecretManager(这个还不明白是做什么用的)。
    FSNamesystem nsys = new FSNamesystem(new FSImage(dirsToFormat,
                                         editDirsToFormat), conf);

    //最后,就是调用FSImage对象来完成format操作了,这也是整个文件系统格式化的核心过程。
    nsys.dir.fsImage.format();

(4)FSImage.format

    //初始化系统的基本信息,包括版本信息,文件系统的编号等

    this.layoutVersion = FSConstants.LAYOUT_VERSION;
    this.namespaceID = newNamespaceID();
    this.cTime = 0L;
    this.checkpointTime = FSNamesystem.now();

    //这个for循环,就是对之前提到的storageDirs列表的遍历,对每个StorageDirectory对象进行format操作
    for (Iterator<StorageDirectory> it = 
                           dirIterator(); it.hasNext();) {
      StorageDirectory sd = it.next();

     //这个功能较简单,主要分两个步骤

     //调用clearDirectory完全删除sd所在的目录,然后再创建空目录
     //调用saveCurrent创建sd目录下的current目录和fsimage目录及相关文件。具体的创建过程就不分析了,下面的部分就对name目录结构进行分析

      format(sd);
    }

(5)saveCurrent(sd)过程分析

File curDir = sd.getCurrentDir(); //获取sd目录下的current目录
    NameNodeDirType dirType = (NameNodeDirType)sd.getStorageDirType(); //读取目录类型,前面说过,有三种
    // save new image or new edits
    if (!curDir.exists() && !curDir.mkdir())
      throw new IOException("Cannot create directory " + curDir);
    if (dirType.isOfType(NameNodeDirType.IMAGE))
//如果是image或imageandedit类型,创建fsimage文件,并写入根目录信息
      saveFSImage(getImageFile(sd, NameNodeFile.IMAGE));
    if (dirType.isOfType(NameNodeDirType.EDITS))
      editLog.createEditLogFile(getImageFile(sd, NameNodeFile.EDITS)); 
//如果是edit或imageandedit类型,创建edits文件,并写入版本信息
    // write version and time files
    sd.write();
//写入支持旧版本的fsimage目录内容、写入版本信息到VERSION文件中、写入当前系统时间到fstime目录中

(6)name目录结构分析

前面很多地方的介绍都省略了,在这里补充上吧,算是对整个fsimage的结构分析

1)current目录:用于保存当前的fsimage和edits文件,以及版本信息和时间信息(用于checkpoint相关)

2)fsimage目录:用于阻止0.13版本以前的hadoop系统启动。在源码中有这样的描述: "This file is INTENTIONALLY CORRUPTED so that versions of Hadoop prior to 0.13 (which are incompatible. with this directory layout) will fail to start."

3)in_use.lock:空文件、全局锁

4)previous.checkpoint:源码中还未找到相关信息,大约是对current的备份,如果namenode挂了,可以从这里恢复current目录的内容。

5)current/fsimage文件:saveFSImage方法,将文件目录和block等信息存放在这个文件中。1.0.3版本中对这个文件的内容是这样存放的:

系统信息:layout(int,版本号)、namespaceID(int,系统ID号,一串随机数)、 numItemsInTree(long,文件数量,用于后面的遍历读取目录结构)、generationStamp(long,从1000开始,用于创 建新的文件时指定文件的版本号)

根据numItemsInTree,遍历文件系统:每个文件或目录在fsimage中的数据结构存放如下,路径名称(hdfs中的路径,不是物理路 径)、副本数量(如果是路径该值为0,如果是文件根据设置的副本数量)、修改时间(long)、atime(尚不知道有何用)、块大小(如果是目录,则这 个值为0)、数据块数量(如果是目录,则为-1;如果是空文件,为0)、nsQuota(尚不明白有何用,仅目录存储这个字段)、dsQuota(尚不明 白有何用,仅目录存储这个字段)、数据块信息(仅文件支持,储存每个数据块信息,包括blockid、block数据块实际使用字节数大小、block版 本号generationstamp)、用户名、组名称、权限

fsimage文件的最后,是Number of files under construction和delegationTokenSequenceNumber这两个信息,目前尚不清楚有何用。

6)current/edits文件:存放文件操作的信息。具体可以查看EditLogFileOutputStream这个类,是日志文件输出流的具体实现类。这个文件主要分为两个部分

版本信息:int类型

操作日志:在FSEditLog类中定义了全局操作变量,有OP_INVALID、OP_ADD = 0、OP_RENAME、OP_DELETE、OP_MKDIR、OP_SET_REPLICATION、OP_DATANODE_ADD、 OP_DATANODE_REMOVE、OP_SET_PERMISSIONS、OP_SET_OWNER 、OP_CLOSE、OP_SET_GENSTAMP、OP_SET_NS_QUOTA 、OP_CLEAR_NS_QUOTA 、OP_TIMES 、OP_SET_QUOTA、 OP_GET_DELEGATION_TOKEN 、OP_RENEW_DELEGATION_TOKEN、 OP_CANCEL_DELEGATION_TOKEN、 OP_UPDATE_MASTER_KEY等。

(7)文件读写方式

在hadoop中,读写上述文件,均通过基本输入输出流DataInputStream和DataOutputStream来实现数据流的读写,文件系统的持久化信息数据文件是二进制文件。

你可能感兴趣的:(NameNode)