1. 程式人生 > >hadoop原始碼學習之namenode啟動

hadoop原始碼學習之namenode啟動

概述

hdfs主要包括兩類節點,namenode和datanode,所以hdfs的啟動也就是這兩類節點的啟動.
namenode管理者所有的datanode資訊、資料塊資訊等,它是整個hdfs的核心,首先要啟動namenode,然後再啟動datanode。

namenode格式化

namenode的class是org.apache.hadoop.hdfs.server.namenode.NameNode,位於hadooop-hdfs專案中,入口方法是main方法,main方法呼叫了靜態方法createNameNode來建立namenode。

在createNameNode方法中,通過switch中的引數來判斷做格式化、升級、啟動等操作,程式碼如下:

    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的資料目錄,初始化叢集的id、版本等,會在配置的目錄寫入相應的屬性檔案.

格式化的主要方法是namenode中的format方法,在這裡主要從配置檔案中讀取相應的配置,做一些相應的檢查,然後構造了兩個hdfs非常核心的類FSImage、FSNamesystem。


FSImage:在硬碟中儲存著hdfs系統的元資料,儲存著在某一個時刻hdfs的映象,後續的各種實時的操作記錄在FSEditLog類中。

FSNamesystem :FSNamesystem does the actual bookkeeping work for the DataNode,這個註釋很好的解釋了FSNamesystem的功能


    FSImage fsImage = new FSImage(conf, nameDirsToFormat, editDirsToFormat);
    try {
      FSNamesystem fsn = new FSNamesystem(conf, fsImage);
      fsImage.getEditLog().initJournalsForWrite();

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

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

最後呼叫了FSImage#format方法進行格式化操作

  void format(FSNamesystem fsn, String clusterId) throws IOException {
    long fileCount = fsn.getTotalFiles();
    // Expect 1 file, which is the root inode
    Preconditions.checkState(fileCount == 1,
        "FSImage.format should be called with an uninitialized namesystem, has " +
        fileCount + " files");
    NamespaceInfo ns = NNStorage.newNamespaceInfo();
    LOG.info("Allocated new BlockPoolId: " + ns.getBlockPoolID());
    ns.clusterID = clusterId;

    storage.format(ns);//進行namenode所有的目錄的格式化,寫屬性檔案
    editLog.formatNonFileJournals(ns);//初始化編輯日誌
    saveFSImageInAllDirs(fsn, 0);//初始化fsimage
  }

namenode的啟動

整體流程

namenode的啟動是直接進入了了上述switch中的default選項,使用配置檔案呼叫構造方法構造了namenode物件

在構造方法中,首先進行了一系列的賦值操作,然後呼叫initialize(Configuration conf)來初始化namenode

首先通過startHttpServer來啟動一個web伺服器,我們可以通過這個web伺服器來查詢hdfs的各種使用情況,其次用loadNamesystem(conf)從磁碟載入元資料到記憶體中,然後 rpcServer = createRpcServer(conf);來初始化namenode的rpc服務。最後startCommonServices(conf);來啟動服務,這個時候namnode的各項服務就初始化完成了。

服務啟動流程詳解

通過FSNamesystem中的startCommonServices方法來啟動服務
namesystem.startCommonServices(conf, haContext);
然後呼叫了org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.activate(Configuration)

  public void activate(Configuration conf) {
    pendingReplications.start();
    datanodeManager.activate(conf);
    this.replicationThread.start();
    this.blockReportThread.start();
  }

pendingReplications

pendingReplications.start()構造了一個PendingReplicationMonitor執行緒並且啟動,
PendingReplicationMonitor的功能參考以下注釋

  /*
   * A periodic thread that scans for blocks that never finished
   * their replication request.
   */
  class PendingReplicationMonitor implements Runnable {
      .................
  }

datanodeManager

datanodeManager.activate(conf);啟動了監控執行緒和心跳處理執行緒

  void activate(final Configuration conf) {
    decomManager.activate(conf);
    heartbeatManager.activate(conf);
  }

replicationThread

初始化副本的監控執行緒ReplicationMonitor並啟動

blockReportThread

初始化塊處理執行緒,對datanode上報的資料塊進行處理,此執行緒為守護執行緒
setDaemon(true);