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的启动流程:

 

posted @ 2020-04-02 22:00  niutao  阅读(1109)  评论(0编辑  收藏  举报