Hadoop源碼分析六啟動(dòng)文件namenode原理詳解
1、 namenode啟動(dòng)
在本系列文章三中分析了hadoop的啟動(dòng)文件,其中提到了namenode啟動(dòng)的時(shí)候調(diào)用的類為
org.apache.hadoop.hdfs.server.namenode.NameNode
其main方法的內(nèi)容如下:
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);
}
}
這段代碼的重點(diǎn)在第8行,這里createNameNode方法創(chuàng)建了一個(gè)namenode對(duì)象,然后調(diào)用其join方法阻塞等待請(qǐng)求。
createNameNode方法的內(nèi)容如下:
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);
}
}
}
這段代碼很簡(jiǎn)單。主要做的操作有三個(gè):
- 1、 創(chuàng)建配置文件對(duì)象
- 2、 解析命令行的參數(shù)
- 3、 根據(jù)參數(shù)執(zhí)行對(duì)應(yīng)方法(switch塊)
其中創(chuàng)建的配置文件的為HdfsConfiguration(第5行),這里的HdfsConfiguration繼承于Configuration類,它會(huì)加載hadoop的配置文件到內(nèi)存中。然后解析傳入main方法的參數(shù),根據(jù)這個(gè)參數(shù)執(zhí)行具體的方法。正常啟動(dòng)的時(shí)候執(zhí)行的default里的內(nèi)容。default的內(nèi)容也很簡(jiǎn)單,就是創(chuàng)建一個(gè)Namenode對(duì)象。
這里先從HdfsConfiguration開始分析,詳細(xì)講解hdfs的配置文件處理。
首先看HdfsConfiguration的初始化方法如下:
public HdfsConfiguration() {
super();
}
這里是調(diào)用其父類的初始化方法。
其父類為Configuration類,它的初始化方法如下:
/** A new configuration. */
public Configuration() {
this(true);
}
這里可以看見他是調(diào)用了一個(gè)重載方法,傳入了一個(gè)參數(shù):true。
接著細(xì)看這個(gè)重載方法:
public Configuration(boolean loadDefaults) {
this.loadDefaults = loadDefaults;
updatingResource = new ConcurrentHashMap<String, String[]>();
synchronized(Configuration.class) {
REGISTRY.put(this, null);
}
}
這里也很簡(jiǎn)單,這里主要是為兩個(gè)參數(shù)賦值,并將新創(chuàng)建的Configuration添加到REGISTRY中。
至此便創(chuàng)建好了一個(gè)配置文件。但是關(guān)于配置文件的初始化解析還未完成。在java里可以使用static關(guān)鍵字聲明一段代碼塊,這段代碼塊在類加載的時(shí)候會(huì)被執(zhí)行。在Configuration和HdfsConfiguration中都有靜態(tài)代碼塊。
首先在Configuration類中,在第682行有一段靜態(tài)代碼塊,其內(nèi)容如下:

這段代碼的重點(diǎn)在第695行和第696行,這里調(diào)用了一個(gè)addDefaultResource方法,這里傳入了兩個(gè)參數(shù)core-default.xml和core-site.xml。其中core-site.xml就是在安裝hadoop的時(shí)候設(shè)置的配置文件。而core-default.xml是hadoop自帶的配置文件,這個(gè)文件可以在hadoop的官方文檔里查到,文檔鏈接如下:https://hadoop.apache.org/docs/r2.7.6/hadoop-project-dist/hadoop-common/core-default.xml
同樣在hadoop的源碼里也有這個(gè)文件,它在hadoop-common-XX.jar中。
接著繼續(xù)分析調(diào)用的addDefaultResource方法
其內(nèi)容如下:
public static synchronized void addDefaultResource(String name) {
if(!defaultResources.contains(name)) {
defaultResources.add(name);
for(Configuration conf : REGISTRY.keySet()) {
if(conf.loadDefaults) {
conf.reloadConfiguration();
}
}
}
}
這段代碼也很簡(jiǎn)單。首先是第二行先從defaultResources中判斷是否已經(jīng)存在該配置文件,
這里的defaultResources是一個(gè)list
其定義如下:
private static final CopyOnWriteArrayList<String> defaultResources =
new CopyOnWriteArrayList<String>();
若defaultResources中不存在這個(gè)配置文件,則繼續(xù)向下執(zhí)行,將這個(gè)配置文件添加到defaultResources中(第3行)。然后遍歷REGISTRY中的key(第4行),這里的key就是在上文提到的Configuration對(duì)象。然后根據(jù)其loadDefaults的值來判斷是否執(zhí)行reloadConfiguration方法。
這里的loadDefaults的值就是上文分析的傳入重載方法的值,上文傳入的為true,所以其創(chuàng)建的Configuration對(duì)象在這里會(huì)執(zhí)行reloadConfiguration方法。
reloadConfiguration方法內(nèi)容如下:
public synchronized void reloadConfiguration() {
properties = null; // trigger reload
finalParameters.clear(); // clear site-limits
}
這里可以看見這個(gè)reloadConfiguration方法并沒有真正的重新加載配置文件而是將properties的值設(shè)置為空。
同樣在HdfsConfiguration也有類似的靜態(tài)代碼塊,在第30行,其內(nèi)容如下:

這里首先調(diào)用了一個(gè)addDeprecatedKeys方法然后調(diào)用了一個(gè)addDefaultResource。這里的addDefaultResource傳了兩個(gè)文件hdfs-default.xml和hdfs-site.xml。其中hdfs-site.xml是安裝時(shí)的配置文件,hdfs-default.xml是其自帶的默認(rèn)文件,同上文的core-default.xml一樣。官網(wǎng)鏈接為:https://hadoop.apache.org/docs/r2.7.6/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml。文件位于:hadoop-hdfs-2.7.6.jar。
其中addDeprecatedKeys方法內(nèi)容如下:
private static void addDeprecatedKeys() {
Configuration.addDeprecations(new DeprecationDelta[] {
new DeprecationDelta("dfs.backup.address",
DFSConfigKeys.DFS_NAMENODE_BACKUP_ADDRESS_KEY),
new DeprecationDelta("dfs.backup.http.address",
DFSConfigKeys.DFS_NAMENODE_BACKUP_HTTP_ADDRESS_KEY),
new DeprecationDelta("dfs.balance.bandwidthPerSec",
DFSConfigKeys.DFS_DATANODE_BALANCE_BANDWIDTHPERSEC_KEY),
new DeprecationDelta("dfs.data.dir",
DFSConfigKeys.DFS_DATANODE_DATA_DIR_KEY),
new DeprecationDelta("dfs.http.address",
DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY),
new DeprecationDelta("dfs.https.address",
DFSConfigKeys.DFS_NAMENODE_HTTPS_ADDRESS_KEY),
new DeprecationDelta("dfs.max.objects",
DFSConfigKeys.DFS_NAMENODE_MAX_OBJECTS_KEY),
new DeprecationDelta("dfs.name.dir",
DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY),
new DeprecationDelta("dfs.name.dir.restore",
DFSConfigKeys.DFS_NAMENODE_NAME_DIR_RESTORE_KEY),
new DeprecationDelta("dfs.name.edits.dir",
DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY),
new DeprecationDelta("dfs.read.prefetch.size",
DFSConfigKeys.DFS_CLIENT_READ_PREFETCH_SIZE_KEY),
new DeprecationDelta("dfs.safemode.extension",
DFSConfigKeys.DFS_NAMENODE_SAFEMODE_EXTENSION_KEY),
new DeprecationDelta("dfs.safemode.threshold.pct",
DFSConfigKeys.DFS_NAMENODE_SAFEMODE_THRESHOLD_PCT_KEY),
new DeprecationDelta("dfs.secondary.http.address",
DFSConfigKeys.DFS_NAMENODE_SECONDARY_HTTP_ADDRESS_KEY),
new DeprecationDelta("dfs.socket.timeout",
DFSConfigKeys.DFS_CLIENT_SOCKET_TIMEOUT_KEY),
new DeprecationDelta("fs.checkpoint.dir",
DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_DIR_KEY),
new DeprecationDelta("fs.checkpoint.edits.dir",
DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_EDITS_DIR_KEY),
new DeprecationDelta("fs.checkpoint.period",
DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_PERIOD_KEY),
new DeprecationDelta("heartbeat.recheck.interval",
DFSConfigKeys.DFS_NAMENODE_HEARTBEAT_RECHECK_INTERVAL_KEY),
new DeprecationDelta("dfs.https.client.keystore.resource",
DFSConfigKeys.DFS_CLIENT_HTTPS_KEYSTORE_RESOURCE_KEY),
new DeprecationDelta("dfs.https.need.client.auth",
DFSConfigKeys.DFS_CLIENT_HTTPS_NEED_AUTH_KEY),
new DeprecationDelta("slave.host.name",
DFSConfigKeys.DFS_DATANODE_HOST_NAME_KEY),
new DeprecationDelta("session.id",
DFSConfigKeys.DFS_METRICS_SESSION_ID_KEY),
new DeprecationDelta("dfs.access.time.precision",
DFSConfigKeys.DFS_NAMENODE_ACCESSTIME_PRECISION_KEY),
new DeprecationDelta("dfs.replication.considerLoad",
DFSConfigKeys.DFS_NAMENODE_REPLICATION_CONSIDERLOAD_KEY),
new DeprecationDelta("dfs.replication.interval",
DFSConfigKeys.DFS_NAMENODE_REPLICATION_INTERVAL_KEY),
new DeprecationDelta("dfs.replication.min",
DFSConfigKeys.DFS_NAMENODE_REPLICATION_MIN_KEY),
new DeprecationDelta("dfs.replication.pending.timeout.sec",
DFSConfigKeys.DFS_NAMENODE_REPLICATION_PENDING_TIMEOUT_SEC_KEY),
new DeprecationDelta("dfs.max-repl-streams",
DFSConfigKeys.DFS_NAMENODE_REPLICATION_MAX_STREAMS_KEY),
new DeprecationDelta("dfs.permissions",
DFSConfigKeys.DFS_PERMISSIONS_ENABLED_KEY),
new DeprecationDelta("dfs.permissions.supergroup",
DFSConfigKeys.DFS_PERMISSIONS_SUPERUSERGROUP_KEY),
new DeprecationDelta("dfs.write.packet.size",
DFSConfigKeys.DFS_CLIENT_WRITE_PACKET_SIZE_KEY),
new DeprecationDelta("dfs.block.size",
DFSConfigKeys.DFS_BLOCK_SIZE_KEY),
new DeprecationDelta("dfs.datanode.max.xcievers",
DFSConfigKeys.DFS_DATANODE_MAX_RECEIVER_THREADS_KEY),
new DeprecationDelta("io.bytes.per.checksum",
DFSConfigKeys.DFS_BYTES_PER_CHECKSUM_KEY),
new DeprecationDelta("dfs.federation.nameservices",
DFSConfigKeys.DFS_NAMESERVICES),
new DeprecationDelta("dfs.federation.nameservice.id",
DFSConfigKeys.DFS_NAMESERVICE_ID),
new DeprecationDelta("dfs.client.file-block-storage-locations.timeout",
DFSConfigKeys.DFS_CLIENT_FILE_BLOCK_STORAGE_LOCATIONS_TIMEOUT_MS),
});
}
這段代碼很簡(jiǎn)單,只有一句話。調(diào)用了 Configuration的靜態(tài)方法addDeprecations,并向其中傳入了一個(gè)參數(shù),參數(shù)類型為DeprecationDelta類的數(shù)組,并為數(shù)組中的數(shù)據(jù)進(jìn)行賦值。
以上就是關(guān)于Hadoop源碼分析啟動(dòng)文件namenode原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Hadoop源碼分析的資料請(qǐng)持續(xù)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
deepseek本地部署及java、python調(diào)用步驟詳解
這篇文章主要介紹了如何下載和使用Ollama模型,包括安裝JDK?17及以上版本和Spring?Boot?3.3.6,配置pom文件和application.yml,創(chuàng)建Controller,以及使用Python調(diào)用模型,需要的朋友可以參考下2025-02-02
Spring Security LDAP實(shí)現(xiàn)身份驗(yàn)證的項(xiàng)目實(shí)踐
在本文中,我們涵蓋了“使用 Spring Boot 的 Spring Security LDAP 身份驗(yàn)證示例”的所有理論和示例部分,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08
SpringBoot+ENC實(shí)現(xiàn)密鑰加密的使用示例
本文主要介紹了SpringBoot+ENC實(shí)現(xiàn)密鑰加密的使用示例,主要是為了將配置信息從應(yīng)用程序代碼中分離出來,以提高安全性和可維護(hù)性,感興趣的可以了解一下2024-07-07
KafkaListener注解的實(shí)現(xiàn)機(jī)制源碼解析
這篇文章主要為大家介紹了KafkaListener注解的實(shí)現(xiàn)機(jī)制源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
JdbcTemplate操作數(shù)據(jù)庫的具體方法
這篇文章主要介紹了JdbcTemplate操作數(shù)據(jù)庫的具體操作方法,準(zhǔn)備工作需要大家先導(dǎo)入相關(guān)的jar包,建個(gè)數(shù)據(jù)庫,具體操作方法跟隨小編一起看看吧2022-03-03
深度源碼解析Java 線程池的實(shí)現(xiàn)原理
如何高效的使用這些資源就是程序員在平時(shí)寫代碼時(shí)候的一個(gè)努力的方向。本文要說的線程池就是一種對(duì) CPU 利用的優(yōu)化手段。對(duì)Java 線程池的實(shí)現(xiàn)原理相關(guān)知識(shí)感興趣的朋友一起看看吧2021-05-05
Spring中@Transactional(rollbackFor=Exception.class)屬性用法介紹
這篇文章介紹了Spring中@Transactional(rollbackFor=Exception.class)屬性的用法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
在 Spring Boot 中使用 @Autowired和 @Bean
本文通過一個(gè)示例演示了如何在SpringBoot中使用@Autowired和@Bean注解進(jìn)行依賴注入和Bean管理,示例中定義了一個(gè)Student類,并通過配置類TestConfig初始化Student對(duì)象,在測(cè)試類中,通過@Autowired注解自動(dòng)注入Student對(duì)象并輸出其屬性值,感興趣的朋友跟隨小編一起看看吧2025-02-02

