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);