Hadoop3.2.1 【 HDFS 】源码分析 : NameNode -format 解析

一.前言

众所周知, 在安装hadoop的时候, 必须对hdfs的Namenode进行格式化操作. 本文主要介绍格式化操作.

 

格式化命令如下.

         bin/hdfs namenode -format

 

二.代码入口

Namenode的格式化操作是 : org.apache.hadoop.hdfs.server.namenode.NameNode

/**
   */
  public static void main(String argv[]) throws Exception {
    //参数校验
    if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) {
      System.exit(0);
    }

    try {
      StringUtils.startupShutdownMessage(NameNode.class, argv, LOG);

      //调用createNameNode()方法创建NameNode对象
      NameNode namenode = createNameNode(argv, null);

      if (namenode != null) {
        //等待Namenode RPC服务结束
        namenode.join();
      }
    } catch (Throwable e) {
      LOG.error("Failed to start namenode.", e);
      //出现异常则直接退出执行
      terminate(1, e);
    }
  }

 

通过main入口的方法,我们可以知道接下来是调用createNameNode方法. 然后根据传入的参数不同执行不同的代码片段.

我们主要是看格式化操作, 我们关注一下 FORMAT 这个代码片段就可以了.

public static NameNode createNameNode(String argv[], Configuration conf)
      throws IOException {
    LOG.info("createNameNode " + Arrays.asList(argv));

    //构建配置文件
    if (conf == null)
      conf = new HdfsConfiguration();

    // Parse out some generic args into Configuration.
    GenericOptionsParser hParser = new GenericOptionsParser(conf, argv);
    argv = hParser.getRemainingArgs();

    // Parse the rest, NN specific args.
    //解析命令行的参数
    StartupOption startOpt = parseArguments(argv);
    if (startOpt == null) {
      printUsage(System.err);
      return null;
    }
    setStartupOption(conf, startOpt);

    boolean aborted = false;

    //根据启动选项调用对应的方法执行操作
    switch (startOpt) {

    //格式化当前Namenode, 调用format()方法执行格式化操作
    case FORMAT:
      aborted = format(conf, startOpt.getForceFormat(),
          startOpt.getInteractiveFormat());
      terminate(aborted ? 1 : 0);
      return null; // avoid javac warning
    case GENCLUSTERID:
      // 代码略...

    //回滚上一次升级, 调用doRollback()方法执行回滚操作。
    case ROLLBACK:
      // 代码略...

    // 拷贝Active Namenode的最新命名空间数据到StandbyNamenode,
    // 调用BootstrapStandby.run()方法执行操作
    case BOOTSTRAPSTANDBY:
     // 代码略...

    //初始化editlog的共享存储空间, 并从Active
    //Namenode中拷贝足够的editlog数据, 使得Standby节点能够顺利启动。 这里调用
    //了静态方法initializeSharedEdits()执行操作
    case INITIALIZESHAREDEDITS:
      // 代码略...
    case BACKUP:


    //启动checkpoint节点, 也是直接构造BackupNode对象并返回。
    case CHECKPOINT:
      // 代码略...

    //恢复损坏的元数据以及文件系统, 这里调用了doRecovery()方法执行操作
    case RECOVER:
      // 代码略...

    //确认配置文件夹存在, 并且打印fsimage文件和文件系统的元数据版本
    case METADATAVERSION:
      // 代码略...

    //升级Namenode, 升级完成后关闭Namenode。
    case UPGRADEONLY:
      // 代码略...


    //在默认情况下直接构造NameNode对象并返回
    default:
      // 初始化 度量服务
      DefaultMetricsSystem.initialize("NameNode");
      //  构建NameNode
      return new NameNode(conf);
    }
  }

 

所以我们主要关注format方法即可.

 

三.格式化操作 format

这里我就不细说了,后面在说FSNamesystem的时候,会做详细讲解. 这里大概就是 生成一个集群id

[clusterId : 规则 CID-UUID 如: CID-d5e21420-46b8-41fb-acc7-8562be611472]

然后构建一个FSImage

// 构建 FSImage
FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);

然后根据FSImage构建和配置文件构建 FSNamesystem, 最后再调用:

fsImage.format(fsn, clusterId, force);

这个进行初始化操作. 生成文件.

/**
   * Verify that configured directories exist, then
   * Interactively confirm that formatting is desired 
   * for each existing directory and format them.
   * 
   * @param conf configuration to use
   * @param force if true, format regardless of whether dirs exist
   * @return true if formatting was aborted, false otherwise
   * @throws IOException
   */
  private static boolean format(Configuration conf, boolean force,  boolean isInteractive) throws IOException {
    // nsId =  null
    String nsId = DFSUtil.getNamenodeNameServiceId(conf);
    // namenodeId =  null
    String namenodeId = HAUtil.getNameNodeId(conf, nsId);

    initializeGenericKeys(conf, nsId, namenodeId);
    //读取配置dfs.namenode.support.allow.format  namenode是否可以格式化: 默认true
    checkAllowFormat(conf);

    if (UserGroupInformation.isSecurityEnabled()) {
      InetSocketAddress socAddr = DFSUtilClient.getNNAddress(conf);
      SecurityUtil.login(conf, DFS_NAMENODE_KEYTAB_FILE_KEY,
          DFS_NAMENODE_KERBEROS_PRINCIPAL_KEY, socAddr.getHostName());
    }
    
    Collection nameDirsToFormat = FSNamesystem.getNamespaceDirs(conf);

    // list 0 : file:/tools/hadoop-3.2.1/data/namenode
    List sharedDirs = FSNamesystem.getSharedEditsDirs(conf);


    List dirsToPrompt = new ArrayList();


    dirsToPrompt.addAll(nameDirsToFormat);
    dirsToPrompt.addAll(sharedDirs);

    // list 0 : file:/tools/hadoop-3.2.1/data/namenode
    List editDirsToFormat =  FSNamesystem.getNamespaceEditsDirs(conf);

    // if clusterID is not provided - see if you can find the current one
    String clusterId = StartupOption.FORMAT.getClusterId();
    if(clusterId == null || clusterId.equals("")) {
      //Generate a new cluster id   生成新的id  举例: CID-UUID  ==>  CID-d5e21420-46b8-41fb-acc7-8562be611472
      clusterId = NNStorage.newClusterID();
    }
    System.out.println("Formatting using clusterid: " + clusterId);
    // 构建 FSImage
    FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);

    //构建 FSNamesystem
    try {
      FSNamesystem fsn = new FSNamesystem(conf, fsImage);
      fsImage.getEditLog().initJournalsForWrite();

      // Abort NameNode format if reformat is disabled and if
      // meta-dir already exists
      if (conf.getBoolean(DFSConfigKeys.DFS_REFORMAT_DISABLED,
          DFSConfigKeys.DFS_REFORMAT_DISABLED_DEFAULT)) {
        force = false;
        isInteractive = false;
        for (StorageDirectory sd : fsImage.storage.dirIterable(null)) {
          if (sd.hasSomeData()) {
            throw new NameNodeFormatException(
                "NameNode format aborted as reformat is disabled for "
                    + "this cluster.");
          }
        }
      }

      if (!fsImage.confirmFormat(force, isInteractive)) {
        return true; // aborted
      }

      //
      fsImage.format(fsn, clusterId, force);


    } catch (IOException ioe) {
      LOG.warn("Encountered exception during format: ", ioe);
      fsImage.close();
      throw ioe;
    }
    return false;
  }

 

四. 格式化后生成的文件&内容

格式化之后,会在配置namenode的目录生成一个current文件夹,里面会有四个文件.

VERSION    记录版本信息
fsimage_0000000000000000000.md5   记录fsimage_0000000000000000000对应的md5
fsimage_0000000000000000000 namenode对应的fsimage文件
seen_txid 事务标识

 

-rw-r--r--@ 1 sysadmin  staff  218  9  6 22:11 VERSION
-rw-r--r--@ 1 sysadmin  staff  401  9  6 22:13 fsimage_0000000000000000000
-rw-r--r--  1 sysadmin  staff   62  9  6 22:13 fsimage_0000000000000000000.md5
-rw-r--r--@ 1 sysadmin  staff    2  9  6 22:11 seen_txid

1.VERSION 文件:


#Sun Sep 06 22:11:02 CST 2020
namespaceID=1147175932
clusterID=CID-d5e21420-46b8-41fb-acc7-8562be611472
cTime=1599401184918
storageType=NAME_NODE
blockpoolID=BP-1598486647-192.168.8.156-1599401184918
layoutVersion=-65

 

2.seen_txid :  只是存储了一个数字 0

 

3.fsimage_0000000000000000000.md5  记录fsimage_0000000000000000000 对应的md5 值

48dd36a9bd6e7ad0ca017afbef91c7cb *fsimage_0000000000000000000

4.fsimage_0000000000000000000

 这里面的内容比较繁琐主要包含以下信息:
 

保存命名空间信息
保存 ErasureCoding 信息
保存命名空间中的inode信息
保存快照信息
保存安全信息
保存缓存信息
保存StringTable

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(Hadoop,3.2.1,源码)