zoukankan      html  css  js  c++  java
  • 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的启动流程:

  • 相关阅读:
    fork()和vfork()的区别(转载)
    Linux中fork()函数详解(转载)
    ERROR:Simulator861-Failed to link the design解决办法
    ISE 14.7安装教程最新版(Win10安装)
    实验2用户及文件权限管理
    检验
    实验1基本概念及操作
    日常学习笔记(2)
    日常笔记1
    拷贝初始化的几种情况
  • 原文地址:https://www.cnblogs.com/niutao/p/12623314.html
Copyright © 2011-2022 走看看