名字节点启动过程介绍

来源:互联网 发布:蓝牙电话软件 编辑:程序博客网 时间:2024/05/22 13:56

一 启动命令

start-dfs.sh中启动NameNode的部分代码:

# namenodesNAMENODES=$($HADOOP_PREFIX/bin/hdfs getconf -namenodes)echo "Starting namenodes on [$NAMENODES]""$HADOOP_PREFIX/sbin/hadoop-daemons.sh" \  --config "$HADOOP_CONF_DIR" \  --hostnames "$NAMENODES" \  --script "$bin/hdfs" start namenode $nameStartOpt

最终调用了hdfs命令:

if [ "$COMMAND" = "namenode" ] ; then  CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode'  HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS" ……  # run it  exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@"

二 主函数

首先判断启动参数是否正确,然后注册了一个关闭钩子,调用createNameNode()创建名字节点类,最后掉哟个join()等待子线程关闭。

  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);      NameNode namenode = createNameNode(argv, null);      if (namenode != null) {        namenode.join();      }    } catch (Throwable e) {      LOG.error("Failed to start namenode.", e);      terminate(1, e);    }  }

三 创建名字节点

在createNameNode()函数中首先获取一个Configuration对象,用于加载启动NameNode节点所需的配置参数。然后就是调用parseArguments()函数来获取运行参数。启动参数StartupOption分为以下几类:

  • FORMAT : 格式化名字节点,启动HDFS集群前需要对名字节点进行格式化,以建立或重新建立名字节点文件结构。
  • GENCLUSTERID : 产生集群ID.
  • FINALIZE : 提交上一次升级,目前NameNode名字不再支持”-finalize”命令,建议用户使用’hdfs dfsadmin -finalizeUpgrade’命令。
  • ROLLBACK : 从升级系统中回滚到前一个版本,这个参数必须在停止的集群分布式文件系统中使用。
  • BOOTSTRAPSTANDBY : 拷贝Active NameNode的最新命名空间到Standby NameNode。
  • INITIALIZESHAREDEDITS : 初始化editlog的共享存储空间,并从Active NameNode中拷贝足够的editlog数据,使得Standby NameNode能够顺利启动。
  • BACKUP/CHECKPOINT: 启动冷备或者温备名字节点。
  • RECOVER : 恢复损坏的元数据以及文件系统。
  • METADATAVERSION : 确认配置文件夹存在,并且打印fsimage文件和文件系统的元数据版本。
  • UPGRADEONLY : 升级NameNode,升级完成后关闭NameNode。
  • REGULAR : 正常启动。
  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);    switch (startOpt) {      case FORMAT: {        boolean aborted = format(conf, startOpt.getForceFormat(),            startOpt.getInteractiveFormat());        terminate(aborted ? 1 : 0);        return null; // avoid javac warning      }      case GENCLUSTERID: {        System.err.println("Generating new cluster id:");        System.out.println(NNStorage.newClusterID());        terminate(0);        return null;      }      case FINALIZE: {        System.err.println("Use of the argument '" + StartupOption.FINALIZE +            "' is no longer supported. To finalize an upgrade, start the NN " +            " and then run `hdfs dfsadmin -finalizeUpgrade'");        terminate(1);        return null; // avoid javac warning      }      case ROLLBACK: {        boolean aborted = doRollback(conf, true);        terminate(aborted ? 1 : 0);        return null; // avoid warning      }      case BOOTSTRAPSTANDBY: {        String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length);        int rc = BootstrapStandby.run(toolArgs, conf);        terminate(rc);        return null; // avoid warning      }      case INITIALIZESHAREDEDITS: {        boolean aborted = initializeSharedEdits(conf,            startOpt.getForceFormat(),            startOpt.getInteractiveFormat());        terminate(aborted ? 1 : 0);        return null; // avoid warning      }      case BACKUP:      case CHECKPOINT: {        NamenodeRole role = startOpt.toNodeRole();        DefaultMetricsSystem.initialize(role.toString().replace(" ", ""));        return new BackupNode(conf, role);      }      case RECOVER: {        NameNode.doRecovery(startOpt, conf);        return null;      }      case METADATAVERSION: {        printMetadataVersion(conf);        terminate(0);        return null; // avoid javac warning      }      case UPGRADEONLY: {        DefaultMetricsSystem.initialize("NameNode");        new NameNode(conf);        terminate(0);        return null;      }      default: {        DefaultMetricsSystem.initialize("NameNode");        return new NameNode(conf);      }    }  }

四 构造名字节点

NameNode的构造函数比较简单,首先解析配置文件,确认当前NameNode是否开启了HA模式,然后对NameNode进行初始化,初始化完成后进入Standby状态,如果出现了异常则停止NameNode服务。

  protected NameNode(Configuration conf, NamenodeRole role)       throws IOException {     this.conf = conf;    this.role = role;    setClientNamenodeAddress(conf);    String nsId = getNameServiceId(conf);    String namenodeId = HAUtil.getNameNodeId(conf, nsId);    this.haEnabled = HAUtil.isHAEnabled(conf, nsId);    state = createHAState(getStartupOption(conf));    this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);    this.haContext = createHAContext();    try {      initializeGenericKeys(conf, nsId, namenodeId);      initialize(conf);      try {        haContext.writeLock();        state.prepareToEnterState(haContext);        state.enterState(haContext);      } finally {        haContext.writeUnlock();      }    } catch (IOException e) {      this.stop();      throw e;    } catch (HadoopIllegalArgumentException e) {      this.stop();      throw e;    }    this.started.set(true);  }

五 初始化名字节点

在initialize内会不仅进行用户的权限验证,加载fsimage,edits到内存;同时也有心跳监控,退役监控,NameNode资源监控,数据块冗余监控等集群监控器;RPC的服务初始化及其重启,HTTP服务的初始化及其启动均在该方法内进行封装实现。

  protected void initialize(Configuration conf) throws IOException {    if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) {      String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY);      if (intervals != null) {        conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS,          intervals);      }    }    UserGroupInformation.setConfiguration(conf);    //用户登录权限验证    loginAsNameNodeUser(conf);    NameNode.initMetrics(conf, this.getRole());    StartupProgressMetrics.register(startupProgress);    if (NamenodeRole.NAMENODE == role) {    //HttpServer启动      startHttpServer(conf);    }    this.spanReceiverHost =      SpanReceiverHost.get(conf, DFSConfigKeys.DFS_SERVER_HTRACE_PREFIX);    //加载元数据,初始化存储目录对象,初始化心跳等管理服务对象,加载命名空间等    loadNamesystem(conf);    //创建RPC相关    rpcServer = createRpcServer(conf);    if (clientNamenodeAddress == null) {      // This is expected for MiniDFSCluster. Set it now using       // the RPC server's bind address.      clientNamenodeAddress =           NetUtils.getHostPortString(rpcServer.getRpcAddress());      LOG.info("Clients are to use " + clientNamenodeAddress + " to access"          + " this namenode/service.");    }    if (NamenodeRole.NAMENODE == role) {      httpServer.setNameNodeAddress(getNameNodeAddress());      httpServer.setFSImage(getFSImage());    }    //启动停顿检测线程    pauseMonitor = new JvmPauseMonitor(conf);    pauseMonitor.start();    metrics.getJvmMetrics().setPauseMonitor(pauseMonitor);    //启动NameNode心跳等监控线程;启动RPC,HTTP服务;启动插件等    startCommonServices(conf);  }

六 元数据文件加载

NameNode将文件系统的管理委托给了FSNamesystem对象,NameNode会调用FSNamesystem.loadFromDisk()创建FSNamesystem对象,然后将fsimage文件和editlog文件加载到命名空间中。

  static FSNamesystem loadFromDisk(Configuration conf) throws IOException {    checkConfiguration(conf);    FSImage fsImage = new FSImage(conf,        FSNamesystem.getNamespaceDirs(conf),        FSNamesystem.getNamespaceEditsDirs(conf));    //创建FSNamesystem对象    FSNamesystem namesystem = new FSNamesystem(conf, fsImage, false);    StartupOption startOpt = NameNode.getStartupOption(conf);    if (startOpt == StartupOption.RECOVER) {      namesystem.setSafeMode(SafeModeAction.SAFEMODE_ENTER);    }    long loadStart = monotonicNow();    try {      //加载元数据文件      namesystem.loadFSImage(startOpt);    } catch (IOException ioe) {      LOG.warn("Encountered exception loading fsimage", ioe);      fsImage.close();      throw ioe;    }    long timeTakenToLoadFSImage = monotonicNow() - loadStart;    LOG.info("Finished loading FSImage in " + timeTakenToLoadFSImage + " msecs");    NameNodeMetrics nnMetrics = NameNode.getNameNodeMetrics();    if (nnMetrics != null) {      nnMetrics.setFsImageLoadTime((int) timeTakenToLoadFSImage);    }    return namesystem;  }

至此NameNode的启动过程就介绍完了。

1 0