Hadoop源码学习笔记之NameNode启动场景流程三:FSNamesystem初始化源码剖析

上篇内容分析了http server的启动代码,这篇文章继续从initialize()方法中按执行顺序进行分析。内容还是分为三大块:

一、源码调用关系分析

二、伪代码执行流程

三、代码图解

 

一、源码调用关系分析

  上一篇内容是NameNode启动http server的分析,是根据锁定NameNode的main()入口,发现了该入口仅有两行核心代码,先进入到了第一行核心代码

  createNameNode()中,发现默认情况是new了一个NameNode对象。在NameNode的构造方法中,有一些很重要的初始化操作,比如启动

  http server、加载元数据、初始化rpc server、安全模式检查等。

  废话不多说,前面的NameNode.main()、createNameNode()、new NameNode()都不再赘述、直接从initialize()说起:

protected void initialize(Configuration conf) throws IOException {
  // 可以通过找到下面变量名的映射,在hdfs-default.xml中找到对应的配置
  if (conf.get(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS) == null) {
    String intervals = conf.get(DFS_METRICS_PERCENTILES_INTERVALS_KEY);
    if (intervals != null) {
      conf.set(HADOOP_USER_GROUP_METRICS_PERCENTILES_INTERVALS,
        intervals);
    }
  }

  ......

  // 核心代码:启动HttpServer
  if (NamenodeRole.NAMENODE == role) {
    startHttpServer(conf);
  }

  this.spanReceiverHost = SpanReceiverHost.getInstance(conf);

  // 核心代码:FSNamesystem初始化
  loadNamesystem(conf);

  // 核心代码:后面rpc server启动流程篇研究
  rpcServer = createRpcServer(conf);
  
  ......
  // 核心代码:启动一些服务组件,包括rpc server等
  startCommonServices(conf);
}

  本篇内容主要是关于管理磁盘元数据的FSNamesystem初始化流程,所以从方法名即可推测loadNamesystem()是需要我们重点关注的核心中的核心。

  点进去:

protected void loadNamesystem(Configuration conf) throws IOException {
    // 核心代码:从磁盘上加载元数据,loadFromDisk()就是从磁盘上读取fsimage和edits文件。
    this.namesystem = FSNamesystem.loadFromDisk(conf);
  }

  我们都知道NameNode的功能之一是,在NameNode启动的时候,会将磁盘上的fsimage和edits两个文件都读取到内存中进行合并,形成一份最新的

  元数据。这份最新的元数据放在哪呢?其实是放在了内存中由FSNamesystem进行管理。真的是这样的吗?我们继续往下看,进入到loadFromDisk():

  /**
   * Instantiates an FSNamesystem loaded from the image and edits
   * directories specified in the passed Configuration.
   *
   * @param conf the Configuration which specifies the storage directories
   *             from which to load
   * @return an FSNamesystem which contains the loaded namespace
   * @throws IOException if loading fails
   */
  static FSNamesystem loadFromDisk(Configuration conf) throws IOException {
    checkConfiguration(conf);
    // 核心代码:构造一个FSImage对象,从NamespaceDirs、NamespaceEditsDirs指定的路径加载
    FSImage fsImage = new FSImage(conf,
        // 默认是从 DFS_NAMENODE_NAME_DIR_KEY 加载fsimage文件
        FSNamesystem.getNamespaceDirs(conf),
        // 默认是从 DFS_NAMENODE_EDITS_DIR_KEY 加载edits文件
        FSNamesystem.getNamespaceEditsDirs(conf));
    // 核心代码:根据指定了fsimage和edits文件路径的fsimage对象,实例化FSNamesystem对象
    FSNamesystem namesystem = new FSNamesystem(conf, fsImage, false);
    StartupOption startOpt = NameNode.getStartupOption(conf);
    if (startOpt == StartupOption.RECOVER) {
      namesystem.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
    }
   ...try {
      // 核心代码:从磁盘上加载数据,在内存中合并数据
      // 在NameNode刚启动的时候,会从磁盘读取fsimage和edits文件到内存中,合并为一份最新的
      // 元数据,然后将这份新的元数据写出到磁盘替换之前旧的fsimage。然后,还会重新打开一个
      // 空的edits文件,以供接下来的元数据变动日志写入。这个loadFSImage()主要就是干了这么一件事情
      // 会在namenode元数据管理研究时进行深入详细剖析。
      namesystem.loadFSImage(startOpt);
    } catch (IOException ioe) {
      ...
    }
   ...
return namesystem; }

  首先这个loadFromDisk()有一段注释,将这个方法的功能和目的说的也很明白了:根据配置文件指定的路径,实例化一个从image和edits加载元数据

  的FSNamesystem对象。下面开始分析核心代码,这段有3行核心代码:

  fsimage = new FSImage(conf, NameSpaceDirs, NameSpaceEditsDirs);

    这行代码是构造了一个FSImage对象,从NameSpaceDirs, NameSpaceEditsDirs分别

    读取fsimage和edits文件。其中NameSpaceDirs和NameSpaceEditsDirs经过溯源分别对应 dfs.namenode.name.dir 和 

    dfs.namenode.shared.edits.dir,这两个属性都可以在hdfs-default.xml中查看和配置。

  FSNamesystem namesystem = new FSNamesystem(conf, fsimage, false);

    根据上面指定了fsimage路径和edits路径的fsimage对象,构造一个FSNamesystem对象。

  namesystem.loadFSImage();

    开始执行loadFSImage()方法,从磁盘上加载数据并在内存中进行合并。

  注意,在合并fsimage和edits形成一份新的元数据之后,会将这份新的元数据写出到磁盘替换旧的fsimage文件,然后还会打开一个新的edits

  文件,以供接下来的元数据变动的日志写入。这些操作都是在loadFSImage()中完成的,具体的进入到该方法中可以详细了解。

 

二、伪代码执行流程

NameNode.main() // 入口函数
  |——createNameNode(); // 通过new NameNode()进行实例化
    |——initialize(); // 方法进行初始化操作
      |——startHttpServer(); // 启动HttpServer
      |——loadNamesystem(); // 加载元数据
        |——loadFromDisk(); // 从磁盘加载数据
          |——new FSImage(); // 实例化FSImage对象
          |——new FSNamesystem(fsImage); // 根据FSImage对象实例化FSNamesystem
          |——loadFSImage(startOpt); // 加载并合并fsimage、edits,然后写出到磁盘
  |——join()

 

三、代码图解  

 

 

 

 

  

posted @ 2019-01-29 17:47  Boven.Qiao  阅读(711)  评论(0编辑  收藏  举报