本文繼續(xù) NameNode 啟動流程源碼剖析,之前講解了
- Namenode 啟動流程跟蹤
- Namenode Httpserver 啟動流程跟蹤
- Namenode 元數(shù)據(jù)加載跟蹤
這次講解下: Namenode 資源檢查和是否進(jìn)入安全模式的判斷
一、 Namenode 安全模式源碼分析:資源檢查
我們在啟動 Namenode 的時候,有時會遇到 Namenode 進(jìn)入安全模式,所以我們一起也來看看這邊吧。Namenode 安全模式的代碼藏的比較隱蔽,而且名字起的也很隨意。
-
在 NameNode 服務(wù)啟動跟蹤 的第 4 步,最后有一句代碼
startCommonServices(conf);這個方法,這個代碼看著很普通,但其實(shí)資源檢查和安全模式都在這里(吐槽下方法名起不直接)
image -
我們進(jìn)入到
startCommonServices(conf);方法,可以看到在rpcServer啟動前,又調(diào)用了namesystem.startCommonServices(conf, haContext);,我們繼續(xù)跟進(jìn):
startCommonServices -
進(jìn)入
namesystem.startCommonServices(conf, haContext);方法后,里面的代碼就要注意了(這里代碼的命名都比較不好,容易忽略)
首先要注意nnResourceChecker = new NameNodeResourceChecker(conf);,NameNodeResourceChecker這個就是 Namenode 的資源檢查,我們跟進(jìn):
startCommonServices -
跟進(jìn)
nnResourceChecker = new NameNodeResourceChecker(conf);后,發(fā)現(xiàn)這里是獲得了很多 Namenode 的資源目錄,包含editlog存儲目錄(共享、非共享)、Namenode 配置文件中配置的必須目錄等,這些目錄都是通過配置文件配置的
然后把這些目錄傳入了addDirToCheck方法,我們繼續(xù)跟進(jìn)addDirToCheck方法
NameNodeResourceChecker -
跟進(jìn)
addDirToCheck方法后,發(fā)現(xiàn)這里把 所有的目錄都包裝成CheckedVolume對象然后又 put 到volumes變量中,volumes變量是個Map集合,到這里第4步中的nnResourceChecker = new NameNodeResourceChecker(conf);構(gòu)造函數(shù)算是執(zhí)行完了,我們繼續(xù)第 4步中的下一步checkAvailableResources()
image -
跟進(jìn)
checkAvailableResources(),后發(fā)現(xiàn)就一行代碼,繼續(xù)跟進(jìn),發(fā)現(xiàn)雖然還是一行代碼,但是這里把第 5步中的volumes當(dāng)做參數(shù)傳過去了,繼續(xù)跟進(jìn)
image
image -
這里就是對所有傳進(jìn)來的目錄都進(jìn)行了校驗(yàn),具體的校驗(yàn)方法就是
resource.isResourceAvailable(),再看看這個方法
isResourceAvailable -
此方法是個抽象方法,需要知道它的實(shí)現(xiàn),我們在第5步的時候知道其實(shí)這些目錄都被封裝成了
CheckedVolume對象,所以這個方法的實(shí)現(xiàn)類就是CheckedVolume。
image -
進(jìn)入
CheckedVolume的isResourceAvailable方法后,發(fā)現(xiàn)這里 其實(shí)就是判斷此目錄的剩余空間是否小于某個值availableSpace < duReserved(這個值是100m,具體看配置吧),如果小于配置的值,則返回false,否則是 true。到這里這邊checkAvailableResources方法的執(zhí)行就完成了。
image
二、Namenode 安全模式源碼分析:block數(shù) 檢查
- 其實(shí)從6~9就是在給
FSNamesystem.hasResourcesAvailable變量賦值為true或false。我們繼續(xù)6中的代碼,也就是startCommonServices中的下一步,這里有這樣一行代碼setBlockTotal();,這個代碼里就是 啟動安全模式 的關(guān)鍵(但是名字起的太普通了)
image - 我們跟進(jìn)
setBlockTotal();,這里先看getCompleteBlocksTotal()方法,看方法名應(yīng)該是獲得 完成的block總數(shù)。這里要解釋下,其實(shí)在 HDFS中的 block 包含兩個狀態(tài) 一個是 Complete ,另一個是 UnderConstruction。這里就是獲得 Complete 狀態(tài)的block數(shù)量。
setBlockTotal - 我們跟進(jìn)
getCompleteBlocksTotal方法看看,看到getBlocksTotal() - numUCBlocks;這個代碼,我們應(yīng)該了解到 complete狀態(tài)的block數(shù)就是使用 總的block減去 UnderConstruction 狀態(tài)的 block數(shù)。具體判斷狀態(tài),就不看了
getCompleteBlocksTotal - 我們繼續(xù)跟進(jìn)
safeMode.setBlockTotal方法,注意到這里計算了兩個值blockThreshold和blockReplQueueThreshold,最后又調(diào)用了checkMode()方法
safeMode.setBlockTotal - 跟進(jìn)
checkMode()方法,此方法中needEnter()如果返回true就會觸發(fā)enter()(enter就是進(jìn)入安全模式),然后我們看看needEnter()方法具體的邏輯
checkMode - 進(jìn)入
needEnter()后,看到代碼比較簡單,就是有三個判斷,只要有任何一個是True,就返回True。那我們仔細(xì)看看這三個條件吧
needEnter
條件1、 (threshold != 0 && blockSafe < blockThreshold)
如果 blcok 閾值不等于0,且 安全模塊(blockSafe) 小于 閾值模塊
blockSafe:只要有一個副本就是 blockSafe條件2、 (datanodeThreshold != 0 && getNumLiveDataNodes() < datanodeThreshold)
如果 dataNode 活躍最小閾值不等于0,且活躍的 DataNodes 小于最小閾值時,進(jìn)入安全模式
datanodeThreshold 默認(rèn)為0,由 dfs.namenode.safemode.min.datanodes 指定
LiveDataNodes: 當(dāng)前時間 - DataNodes 心跳最后的時間 < 10分30秒條件3、(!nameNodeHasResourcesAvailable());
如果,NameNode 資源檢查無效,進(jìn)入安全模式
三、Namenode 安全模式源碼分析:獲取Datanode活躍數(shù)
前兩節(jié)分析的就是 第1個條件和第3個條件,而第2個條件并沒有分析,我們這一節(jié)就看看這個代碼。

- 先看
datanodeThreshold在哪里賦值的,通過搜索發(fā)現(xiàn)該變量是在配置文件中配置的,dfs.namenode.safemode.min.datanodes,默認(rèn)值是0,所以默認(rèn)情況下,2 這個條件直接就不判斷了。但是我們還可以繼續(xù)看看判斷Datanode活躍的代碼。
image - 跟進(jìn)
getNumLiveDataNodes(),看到就一句代碼
image - 繼續(xù)跟進(jìn)
.getNumLiveDataNodes();,可以看到,判斷Datanode是否活躍的主要代碼其實(shí)就是!isDatanodeDead(dn),也就是說,不是死亡的 datanode就是活躍的
image - 繼續(xù)跟進(jìn)
!isDatanodeDead(dn),可以看到就一句代碼,此代碼就是計算 datanode是否死亡的代碼。node.getLastUpdateMonotonic()就是最后一次心跳的時間 ,monotonicNow()就是當(dāng)前時間,heartbeatExpireInterval是心跳過期間隔;
所以計算公式就是:
如果 當(dāng)前時間 - 最后一次心跳時間 > 心跳過期間隔 那么就認(rèn)為Datanode死亡了。
image - 最后看看
heartbeatExpireInterval是多少呢?
heartbeatRecheckInterval默認(rèn)是5分鐘,heartbeatIntervalSeconds默認(rèn)是3秒,他們在配置文件里都有配置,具體代碼就不跟了。
image
4. 總結(jié)
到此:Namenode 安全模式的代碼就分析完了。這里畫個圖簡單的描述情況





















