3、namenode啟動過程中的資源檢查,以及如何退出安全模式


 

 

 代碼流程:

NameNode.main() // 入口函數
       |——createNameNode(); // 通過new NameNode()進行實例化
         |——initialize(); // 方法進行初始化操作
           |——startHttpServer(); // 啟動HttpServer
           |——loadNamesystem(); // 加載元數據
           |——createRpcServer(); // 創建並初始化rpc server實例
           |——startCommonServices();
             |——namesystem.startCommonServices(); // 啟動一些磁盤檢查、安全模式等一些后台服務及線程
               |——new NameNodeResourceChecker(); // 實例化一個NameNodeResourceChecker並准備出所有需要檢查的磁盤路徑
               |——checkAvailableResources(); // 開始磁盤空間檢查
               |——NameNode.getStartupProgress(); // 獲取StartupProgress實例用來獲取NameNode各任務的啟動信息
               |——setBlockTotal(); // 設置所有的block,用於后面判斷是否進入安全模式
               |——blockManager.activate(); // 啟動BlockManager里面的一堆關於block副本處理的后台線程
             |——rpcServer.start(); // 啟動rpcServer
       |——join()

所以直接查看startCommonServices代碼:

 

 

 1、總體介紹

1、 檢查資源情況、判斷是否進入安全狀態、激活BlockManager
2、啟動RPC服務
 1 /**
 2    * 1、 namesystem.startCommonServices(conf, haContext);
 3    * 檢查資源情況、判斷是否進入安全狀態、激活BlockManager
 4    * 2、啟動RPC服務
 5    * */
 6   private void startCommonServices(Configuration conf) throws IOException {
 7     //FSNamesystem是NameNode核心成員變量用來管理元數據(實現對DataNode、Block的管理以及讀寫日志)
 8     //創建NameNodeResourceChecker、激活BlockManager等
 9     namesystem.startCommonServices(conf, haContext);
10     registerNNSMXBean();//注冊一個namenode的狀態類
11     // 角色非`NamenodeRole.NAMENODE`的在此處啟動HttpServer
12     if (NamenodeRole.NAMENODE != role) {
13       startHttpServer(conf);
14       httpServer.setNameNodeAddress(getNameNodeAddress());
15       httpServer.setFSImage(getFSImage());
16     }
17     //啟動服務
18     rpcServer.start();//
19     plugins = conf.getInstances(DFS_NAMENODE_PLUGINS_KEY,
20         ServicePlugin.class);
21     for (ServicePlugin p: plugins) {
22       try {
23         p.start(this);
24       } catch (Throwable t) {
25         LOG.warn("ServicePlugin " + p + " could not be started", t);
26       }
27     }
28     LOG.info(getRole() + " RPC up at: " + rpcServer.getRpcAddress());
29     if (rpcServer.getServiceRpcAddress() != null) {
30       LOG.info(getRole() + " service RPC up at: "
31           + rpcServer.getServiceRpcAddress());
32     }
33   }

 

2、namesystem.startCommonServices(conf, haContext);檢查資源

 

 

 整體大致邏輯:

1、將需要檢查的URL添加到volumes中 , 后台有線程會一直執行hasAvailableDiskSpace來檢查
2、checkAvailableResources(); 進行資源檢查
3、NameNode啟動,進入到safemode階段,處於一個等待匯報blocks的狀態
4、匯報所有的block,用於后面判斷是否進入安全模式
5、激活BlockManager
/** 
   * 1、將需要檢查的URL添加到volumes中 , 后台有線程會一直執行hasAvailableDiskSpace來檢查
   * 2、checkAvailableResources(); 進行資源檢查
   * 3、NameNode啟動,進入到safemode階段,處於一個等待匯報blocks的狀態
   * 4、匯報所有的block,用於后面判斷是否進入安全模式
   * 5、激活BlockManager
   */
  void startCommonServices(Configuration conf, HAContext haContext) throws IOException {
      this.registerMBean(); // register the MBean for the FSNamesystemState
      writeLock();
      this.haContext = haContext;
      try {
          //NameNodeResourceChecker負責檢查磁盤資源。
        // active狀態的namenod會啟動一個監控線程NameNodeResourceMonitor,
          // 定期執行NameNodeResourceChecker#hasAvailableDiskSpace()檢查可用的磁盤資源。
          /**需要檢查3個涉及到元數據的目錄:
           * Namenode2個目錄:fsimage、editlog(默認情況下這兩個是在同一個目錄)
           * 高可用模式下的journalNode里面也有存儲袁術的目錄
           * */
          nnResourceChecker = new NameNodeResourceChecker(conf);
          //檢查可用資源是否足夠:如果不夠,日志打印警告信息,然后進入安全模式
          checkAvailableResources();
          // 判斷是否進入安全模式,並且副本隊列是否應該被同步/復制
          /**
           * 磁盤資源不足的情況下,任何對元數據修改所產生的日志都無法確保能夠寫入到磁盤,
           * 即新產生的edits log和fsimage都無法確保寫入磁盤。所以要進入安全模式,
           * 來禁止元數據的變動以避免往磁盤寫入新的日志數據
           * */
          assert safeMode != null && !isPopulatingReplQueues();
          //獲取StartupProgress實例用來獲取NameNode各任務的啟動信息
          StartupProgress prog = NameNode.getStartupProgress();
          // 目前NameNode啟動,進入到safemode階段,處於一個等待匯報blocks的狀態
          prog.beginPhase(Phase.SAFEMODE);
          //處於一個等待匯報blocks的狀態
          prog.setTotal(Phase.SAFEMODE, STEP_AWAITING_REPORTED_BLOCKS, getCompleteBlocksTotal());
          //設置所有的block,用於后面判斷是否進入安全模式
          setBlockTotal();
          //TODO 啟動BlockManager里面關於block副本處理的后台線程
          //激活BlockManager
          blockManager.activate(conf);
      } finally {
          writeUnlock();
      }
    
    registerMXBean();
    DefaultMetricsSystem.instance().register(this);
    if (inodeAttributeProvider != null) {
      inodeAttributeProvider.start();
      dir.setINodeAttributeProvider(inodeAttributeProvider);
    }
    snapshotManager.registerMXBean();
  }

3、NameNodeResourceChecker檢查資源類

 

 

 

 

 

 addDirToCheck方法:

 

 

 還有就是,在NameNodeResourceChecker構造方法中,我們得到了duReserved是100M,那么他在哪里使用的?

1):

 

 

 2):

 

 

 3):

 

 

 

 

 

 

 

 

 

 

 

 最后就是areResourcesAvailable這個方法,主要對volumns里面的url進行檢查,看看這些url路徑是否可用,是否滿足繼續運行的最小資源數

 

 

 其中的isResourceAvailable方法就是檢查磁盤空間的:

 

 

 最后在計算是否滿足繼續運行需要的最少數量

 

 

 然后程序返回到NameNodeResourceMonitor這個監控線程地方:

 

 

 

所以說這個NameNodeResourceChecker(磁盤資源檢查類),主要是干了3件事:

1、聲明namenode容忍的磁盤大小的閾值(100M)

2、封裝好需要檢查的磁盤路徑

3、將需要檢查的磁盤路徑通過addDirToCheck方法添加到volumes這個map集合里面, 然后在FSNameSystem中有一個NameNodeResourceMonitor線程,不斷的調用checkAvailableResources方法 來檢查volumes(磁盤的資源情況)

 4):checkAvailableResources

這個checkAvailableResources就是剛剛講解的;

只不過在初始化nameNode的時候會主動檢查一次,啟動后就會通過NameNodeResourceMonitor這個線程不斷的去檢查(每隔1秒去檢查一遍)

ok,這個關於磁盤資源檢查的部分說完了,接下來就是看看startCommonServices方法里面剩余部分

5):剩下的部分

通過StartUpPrpcess(NameNode任務的啟動信息)來指示namenode的運行狀態,namenode啟動后,首先是進入安全模式,然后等待blocks狀態匯報,只有blocks滿足了最低指標需求(0.999f),才會退出安全模式

 

 

 

6):getCompleteBlocksTotal

這里面有個關鍵點就是,通過prog.setTotal來匯報blocks的狀態,那么blocks的狀態怎么拿到?

答案就是通過:getCompleteBlocksTotal這個方法拿到

 

 

 

然后拿到總數據塊 - 無法讀取的數據塊 = 目前可用的數據塊

緊接着就是getNumUnderConstructionBlocks

這段代碼就是獲取非Complete

 

 

 此處處理完畢之后,返回看setBlockTotal()方法

7):setBlockTotal()

設置所有的block,用於后面判斷是否進入安全模式

 

 

 

 

 

 

 

 注意其中的blockSafe:是datanode向namenode進行匯報的塊個數,通過incrementSafeBlockCount方法,不斷的疊加起來的

 

 

 當datanode向namenode匯報刪除數據塊的時候,此處就對blockSafe減小

 

 

 

8):checkMode

其中還有一個關鍵點就是checkMode

用於檢查安全模式的狀態:
1、判斷閾值系數是否滿足進入安全模式:needEnter
對於離開安全模式,有兩個條件判斷:
1、判斷系數是否滿足離開安全模式
2、啟動SafeModeMonitor線程,每隔1秒去查看下,是否可以退出安全模式

 

 如果要是進入了安全模式,那么這個enter()方法里面會把this.reached = 0;

 

 看下needEnter()方法

9):needEnter()

所以需要看一下,是否需要進入安全模式的條件:needEnter()

 

 

 其次就是在checkMode中,除了進入安全模式以外,還有退出安全模式的邏輯

 

 10):后台線程:SafeModeMonitor的代碼

 

 

這個SafeModeMonitor里面這個 判斷是否能夠退出安全模式的依據就是:

canLeave代碼

11):canLeave

然后在看下canLeave的代碼邏輯:

 

 ok。這樣我們整體的startCommonServices代碼就完事了;

總體namenode的啟動流程:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM