
閱讀源碼第一步是要編譯源碼;
源碼版本:hadoop2.6+ ~ hadoop2.7 這個范圍均可,改動不是特別大
編譯源碼教程連接:https://www.jianshu.com/p/a66ab0235fb9
https://www.cnblogs.com/hequn/articles/4839689.html
ps. 編譯出錯很常見不要慌 ,只要確保hadoop需要的依賴是正確的(比如protocol),就沒問題!
1、查看源碼NameNode類
在namenode中有一段main函數,說明 我們通過命令啟動namenode的時候,肯定是通過這個main函數來執行的(腳本:hadoop-daemon.sh 、hdfs):
1 public static void main(String argv[]) throws Exception { 2 if (DFSUtil.parseHelpArgument(argv, NameNode.USAGE, System.out, true)) { 3 System.out.println("####參數校驗#####"); 4 System.exit(0); 5 //hadooop namenode -format 6 //hadoop -datemon.sh start namenode 7 //hadoop-datemon.sh start nn 8 } 9 10 try { 11 //啟動打印日志 12 StringUtils.startupShutdownMessage(NameNode.class, argv, LOG); 13 //TODO 創建NameNode核心代碼 14 NameNode namenode = createNameNode(argv, null); 15 if (namenode != null) { 16 //就是線程的join 17 //會使主線程進入等待池並等待t線程執行完畢后才會被喚醒 18 namenode.join(); 19 } 20 } catch (Throwable e) { 21 LOG.error("Failed to start namenode.", e); 22 terminate(1, e); 23 } 24 }
2、查看核心代碼:createNameNode
NameNode namenode = createNameNode(argv, null);
點擊進入createNameNode(argv , null)函數
顯然我們是啟動namenode,所有都匹配不上,因此會走最后一段
1 public static NameNode createNameNode(String argv[], Configuration conf) 2 throws IOException { 3 LOG.info("createNameNode " + Arrays.asList(argv)); 4 if (conf == null) 5 conf = new HdfsConfiguration(); 6 StartupOption startOpt = parseArguments(argv); 7 if (startOpt == null) { 8 printUsage(System.err); 9 return null; 10 } 11 //將啟動參數加入到配置中 12 setStartupOption(conf, startOpt); 13 /** 14 * 我們在集群中操作 , 比如 : 15 * hdfs namenode -format 16 * hadoop fs -put XXX / 17 * 正常情況下,是先啟動namenode 18 * hadoop-daemon.sh start namenode 19 * */ 20 switch (startOpt) { 21 //格式化 22 case FORMAT: {//hadoop namenode -format 23 boolean aborted = format(conf, startOpt.getForceFormat(), 24 startOpt.getInteractiveFormat()); 25 terminate(aborted ? 1 : 0); 26 return null; // avoid javac warning 27 } 28 // 產生集群ID. 29 case GENCLUSTERID: { 30 System.err.println("Generating new cluster id:"); 31 System.out.println(NNStorage.newClusterID()); 32 terminate(0); 33 return null; 34 } 35 //定版本 36 case FINALIZE: { 37 System.err.println("Use of the argument '" + StartupOption.FINALIZE + 38 "' is no longer supported. To finalize an upgrade, start the NN " + 39 " and then run `hdfs dfsadmin -finalizeUpgrade'"); 40 terminate(1); 41 return null; // avoid javac warning 42 } 43 //回滾 44 case ROLLBACK: { 45 boolean aborted = doRollback(conf, true); 46 terminate(aborted ? 1 : 0); 47 return null; // avoid warning 48 } 49 //同步active節點的快照(配置完HA需要運行這個命令同步active節點的快照(配置完HA需要運行這個命令 50 case BOOTSTRAPSTANDBY: { 51 String toolArgs[] = Arrays.copyOfRange(argv, 1, argv.length); 52 int rc = BootstrapStandby.run(toolArgs, conf); 53 terminate(rc); 54 return null; // avoid warning 55 } 56 //向備用節點共享一組edits日志 57 case INITIALIZESHAREDEDITS: { 58 boolean aborted = initializeSharedEdits(conf, 59 startOpt.getForceFormat(), 60 startOpt.getInteractiveFormat()); 61 terminate(aborted ? 1 : 0); 62 return null; // avoid warning 63 } 64 //啟動冷備或者溫備名字節點 65 case BACKUP: 66 case CHECKPOINT: { 67 NamenodeRole role = startOpt.toNodeRole(); 68 DefaultMetricsSystem.initialize(role.toString().replace(" ", "")); 69 return new BackupNode(conf, role); 70 } 71 //恢復損壞的元數據以及文件系統 72 case RECOVER: { 73 NameNode.doRecovery(startOpt, conf); 74 return null; 75 } 76 //檢查配置的正確性 77 case METADATAVERSION: { 78 printMetadataVersion(conf); 79 terminate(0); 80 return null; // avoid javac warning 81 } 82 //以升級的方式啟動 83 case UPGRADEONLY: { 84 DefaultMetricsSystem.initialize("NameNode"); 85 new NameNode(conf); 86 terminate(0); 87 return null; 88 } 89 //正常啟動NameNode 90 default: { 91 //初始化metric系統 92 DefaultMetricsSystem.initialize("NameNode"); 93 //TODO 94 return new NameNode(conf); 95 } 96 } 97 }
NameNode這個類,里面有一些成員變量,還是很重要,很常見的;比如
1 //NameNode核心成員變量用來管理元數據(實現對DataNode、Block的管理以及讀寫日志) 2 protected FSNamesystem namesystem; 3 //保存配置文件的信息 4 protected final Configuration conf; 5 //保存NameNode的角色信息 6 protected final NamenodeRole role; 7 //保存NameNode的狀態(HA) 8 private volatile HAState state; 9 //是否開啟了高可用(HA) 10 private final boolean haEnabled; 11 //高可用上下文 12 private final HAContext haContext; 13 //NameNode核心成員變量提供RPC服務(提供RPC服務是DataNode和NameNode通信和外部命令管理NameNode的窗口) 14 private NameNodeRpcServer rpcServer;
在這個Namenode的構造參數里面,主要是:
1、對namenode做參數的設置(fs.defaultFS、rpc地址等)
2、初始化
3、根據初始化處理的結果,namenode進入對應的狀態(active、backup、standby)
1 /** 2 * 1、對namenode做參數的注冊(fs.defaultFS、rpc地址等) 3 * 2、初始化 4 * 3、根據初始化處理的結果,namenode進入對應的狀態(active、backup、standby) 5 * */ 6 protected NameNode(Configuration conf, NamenodeRole role) 7 throws IOException { 8 this.conf = conf; 9 this.role = role;//保存NameNode的角色信息 10 //設置clients訪問nomenode或nameservice的訪問地址 配置項fs.defaultFS:hadoop01:9000 11 setClientNamenodeAddress(conf); 12 String nsId = getNameServiceId(conf); 13 String namenodeId = HAUtil.getNameNodeId(conf, nsId); 14 //ha相關 15 this.haEnabled = HAUtil.isHAEnabled(conf, nsId); 16 //根據用戶設置的啟動參數,確定啟動以后的初始狀態,如果是正常啟動,則全部直接進入Standby狀態 17 state = createHAState(getStartupOption(conf)); 18 this.allowStaleStandbyReads = HAUtil.shouldAllowStandbyReads(conf); 19 //TODO 在創建HA的時候,也啟動了standByNameNode的服務 20 this.haContext = createHAContext(); 21 22 23 24 try { 25 //給聯邦模式下准備的,主要是設置聯邦模式下namenode的地址和RPC地址 26 initializeGenericKeys(conf, nsId, namenodeId); 27 //TODO 28 initialize(conf); 29 // HA相關 30 try { 31 haContext.writeLock(); 32 state.prepareToEnterState(haContext); 33 state.enterState(haContext); 34 } finally { 35 haContext.writeUnlock(); 36 } 37 } catch (IOException e) { 38 this.stop(); 39 throw e; 40 } catch (HadoopIllegalArgumentException e) { 41 this.stop(); 42 throw e; 43 } 44 this.started.set(true); 45 }
那么關鍵信息 就是initialize,所以我們接下來重點來看initialize
initialize代碼塊包含了:
1、metrics監控的信息設置 2、hadoop的kerberos的安全認證 3、啟動namendoe的web服務 4、加載元數據 5、創建RPC 6、啟動公共服務startCommonServices (比如:啟動RPC , 啟動磁盤資源檢查線程等工作)
具體內容,下一篇介紹
