HDFS2.X源碼分析之:NameNode啓動流程分析


目前,NameNode有多種啓動:HA方式的從節點,非HA方式的主節點,BackUp(checkpoint)節點

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: {
        boolean aborted = finalize(conf, true);
        terminate(aborted ? 1 : 0);
        return null; // avoid javac 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;
      }
      default: {
        DefaultMetricsSystem.initialize("NameNode");
//以HA方式從節點方式啓動或者non-HA方式啓動
        return new NameNode(conf);
      }

在此主要對NameNode方法進行分析。在該方法中,如果HDFS配置成HA模式,則NameNode以從節點方式啓動,如果配置成非HA模式,則以主節點方式啓動,即對於非HA模式來說,NameNode以主節點方式運行,

protected NameNode(Configuration conf, NamenodeRole role)
      throws IOException {
    this.conf = conf;
    this.role = role;
    String nsId = getNameServiceId(conf);
    String namenodeId = HAUtil.getNameNodeId(conf, nsId);
this.haEnabled = HAUtil.isHAEnabled(conf, nsId);
//非HA模式以主節點方式啓動
    if (!haEnabled) {
      state = ACTIVE_STATE;
/ /HA模式以從節點方式啓動
    } else {
      state = STANDBY_STATE;
    }
    this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf);
    this.haContext = createHAContext();
    try {
      initializeGenericKeys(conf, nsId, namenodeId);
//初始化HA,非HA共同需要的服務
      initialize(conf);
//目前什麼都沒有做??
      state.prepareToEnterState(haContext);
//HA方式啓動與主節點相關服務,非HA方式以從節點方式啓動
      state.enterState(haContext);
    } catch (IOException e) {
      this.stop();
      throw e;
    } catch (HadoopIllegalArgumentException e) {
      this.stop();
      throw e;
    }
  }

在NameNode啓動過程中,有兩個方法值得注意,initialize與enterState方法,前一個方法會初始化HA與非HA共同需要的服務,而enterState則決定了主從節點的特有的服務,這樣設計的好處也是顯而易見的。在initialize內會不僅進行用戶的權限驗證,加載fsimage,edits到內存;同時也有心跳監控,退役監控,NameNode資源監控,數據塊冗餘監控等集羣監控器;RPC的服務初始化及其重啓,HTTP服務的初始化及其啓動均在該方法內進行封裝實現。

protected void initialize(Configuration conf) throws IOException {
    UserGroupInformation.setConfiguration(conf);
    loginAsNameNodeUser(conf);//用戶登陸驗證權限
 
NameNode.initMetrics(conf, this.getRole());
//初始化存儲目錄對象,初始化心跳等管理服務對象,加載命名空間等
    loadNamesystem(conf);
//初始化RPC相關
    rpcServer = createRpcServer(conf);
   
    try {
      validateConfigurationSettings(conf);
    } catch (IOException e) {
      LOG.fatal(e.toString());
      throw e;
    }
//啓動NameNode心跳等監控線程;啓動RPC,HTTP服務
    startCommonServices(conf);
  }
FSNamesystem,FSImage,FSDirectory,BlockManager等均在loadNamesystem下面調用的方法loadFromDisk中進行初始化,調用關係爲:NameNode. Initialize()->NameNode. loadNamesystem()->FSNamesystem.loadFromDisk()->FSNamesystem.loadFromDisk()(注:後兩次調用了重構方法)

public static FSNamesystem loadFromDisk(Configuration conf,
      Collection<URI> namespaceDirs, List<URI> namespaceEditsDirs)
      throws IOException {
 
    if (namespaceDirs.size() == 1) {
      LOG.warn("Only one image storage directory ("
          + DFS_NAMENODE_NAME_DIR_KEY + ") configured. Beware of dataloss"
          + " due to lack of redundant storage directories!");
    }
    if (namespaceEditsDirs.size() == 1) {
      LOG.warn("Only one namespace edits storage directory ("
          + DFS_NAMENODE_EDITS_DIR_KEY + ") configured. Beware of dataloss"
          + " due to lack of redundant storage directories!");
    }
//初始化image,edits,sharedits目錄,和FSEdits對象
FSImage fsImage = new FSImage(conf, namespaceDirs, namespaceEditsDirs);
//初始化BlockManager,FSDirectory,SafeModeInfo等對象
    FSNamesystem namesystem = new FSNamesystem(conf, fsImage);
    StartupOption startOpt = NameNode.getStartupOption(conf);
    if (startOpt == StartupOption.RECOVER) {
      namesystem.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
    }
 
    long loadStart = now();
    String nameserviceId = DFSUtil.getNamenodeNameServiceId(conf);
加載fsimage,fsedits的入口   
namesystem.loadFSImage(startOpt, fsImage,
      HAUtil.isHAEnabled(conf, nameserviceId));
BlockManager在Hadoop0.20版本里面是沒有這個概念的,它將DatanodeManager,HeartbeatManager,BlockTokenSecretManager,BlocksMap,BlockPlacementPolicy等封裝在了一起,至於爲什麼進行這樣的封裝,我想作者是想把塊相關的內容進行統一管理,這樣設計也顯得更加清晰。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章