目前,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等封裝在了一起,至於爲什麼進行這樣的封裝,我想作者是想把塊相關的內容進行統一管理,這樣設計也顯得更加清晰。