NameNode在内存中保存着整个文件系统的名字空间和文件数据块的地址映射(Blockmap)。如果NameNode宕机,那么整个集群就瘫痪了
整个HDFS可存储的文件数受限于NameNode的内存大小
这个关键的元数据结构设计得很紧凑,因而一个有4G内存的Namenode就足够支撑大量的文件和目录。

一般情况下,单namenode集群的最大集群规模为4000台

NameNode负责:文件元数据信息的操作以及处理客户端的请求
NameNode管理:HDFS文件系统的命名空间NameSpace。
NameNode维护:文件系统树(FileSystem)以及文件树中所有的文件和文件夹的元数据信息(matedata) 
        维护文件到块的对应关系和块到节点的对应关系
NameNode文件:namespace镜像文件(fsimage),操作日志文件(edit log)
        这些信息被Cache在RAM中,当然这两个文件也会被持久化存储在本地硬盘。
NameNode记录:每个文件中各个块所在的数据节点的位置信息。
        但它并不永久保存块的位置信息,因为这些信息在系统启动时由数据节点重建。
        从数据节点重建:在nameNode启动时,DataNode向NameNode进行注册时发送给NameNode

1、NameNode元数据信息
文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个文件的块列表。
以及列表中的块与块所在的DataNode之间的地址映射关系
在内存中加载文件系统中每个文件和每个数据块的引用关系(文件、block、datanode之间的映射信息)
数据会定期保存到本地磁盘,但不保存block的位置信息而是由DataNode注册时上报和在运行时维护

2、NameNode文件操作
NameNode负责文件元数据的操作
DataNode负责处理文件内容的读写请求,数据流不经过NameNode,会询问它跟那个DataNode联系

3、NameNode副本
文件数据块到底存放到哪些DataNode上,是由NameNode决定的,NN根据全局情况做出放置副本的决定
读取文件的时候,NN尽量让client读取离它最近的datanode上的副本,降低带宽消耗和读取时延

4、NameNode职责
全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包含该DataNode上所有数据块的列表)
若接受到心跳信息,NN认为DN工作正常,如果在10分钟后还接受到不到DN的心跳,那么NN认为DN已经宕机
这时候NN准备要把DN上的数据块进行重新的复制。
块的状态报告包含了一个DN上所有数据块的列表,blocks report 每个1小时发送一次

5、NameNode容错机制
没有Namenode,HDFS就不能工作。事实上,如果运行namenode的机器坏掉的话,系统中的文件将会完全丢失,因为没有其他方法能够将位于不同datanode上的文件块(blocks)重建文件。因此,namenode的容错机制非常重要,Hadoop提供了两种机制。

第一种方式是将持久化存储在本地硬盘的文件系统元数据备份。Hadoop可以通过配置来让Namenode将他的持久化状态文件写到不同的文件系统中。这种写操作是同步并且是原子化的。比较常见的配置是在将持久化状态写到本地硬盘的同时,也写入到一个远程挂载的网络文件系统(NFS)。

第二种方式是运行一个辅助的Namenode(SecondaryNamenode)。 事实上SecondaryNamenode并不能被用作Namenode它的主要作用是定期的将Namespace镜像与操作日志文件(edit log)合并,以防止操作日志文件(edit log)变得过大。通常,SecondaryNamenode 运行在一个单独的物理机上,因为合并操作需要占用大量的CPU时间以及和Namenode相当的内存。辅助Namenode保存着合并后的Namespace镜像的一个备份,万一哪天Namenode宕机了,这个备份就可以用上了。

但是辅助Namenode总是落后于主Namenode,所以在Namenode宕机时,数据丢失是不可避免的。在这种情况下,一般的,要结合第一种方式中提到的远程挂载的网络文件系统(NFS)中的Namenode的元数据文件来使用,把NFS中的Namenode元数据文件,拷贝到辅助Namenode,并把辅助Namenode作为主Namenode来运行。

6、NameNode物理结构

master节点 /home/wuhuan/hadoopdata/dfs/name,namesecondary 
  name/current,in_user.lock
    in_use.lock  是一个锁,用来保证namenode的唯一性
    current 就是当前namenode存储元数据的目录
    current/edits  --- 对hdfs进行读写操作时产生的元数据的记录文件
    current/fsimage  ---- 镜像文件,是edits经过secondaryNamenode合并后产生的高密度镜像文件。


VERSION:
  其中namespaceID是文件系统的唯一标识符,当文件系统第一次被格式化的时候会被创建
  这个标识符也要求所有的DataNode节点和NameNode保持一致
  NameNode会使用它识别新的DataNode,DataNode只有在向NameNode注册后才会获取namespaceID

Edit Log

edits为二进制文件,记录对HDFS的各种更新操作,客户端执行所有的写操作都会被记录到editlog中。
比如创建文件,删除文件。打开、关闭、重命名文件和目录,都会生成一个edit记录。

客户端对hdfs进行写文件时会首先被记录在edits文件中。
edits修改时元数据也会更新。每次hdfs更新时edits先更新后客户端才会看到最新信息。

namespace Image

fsimage为二进制文件,保存了最新的元数据检查点,包含了整个HDFS文件系统的所有目录和文件信息。
    对于目录来说包括修改时间、访问权限控制信息(目录所属用户,所在组)等。
    对于文件来说包括数据块描述信息、修改时间、访问时间等;

简单的说,Fsimage就是在某一时刻,整个hdfs的快照
就是这个时刻hdfs上所有的文件块和目录,分别的状态,位于哪些个datanode,各自的权限,副本个数等。
【注意】Block的位置信息不会保存到fsimage,由DataNode在向NameNode进行注册时重新加载和定期加载。

一般开始时对namenode的操作都放在edits中,为什么不放在fsimage中呢?
    因为fsimage是namenode的完整的镜像,内容很大
    如果每次都加载到内存的话生成树状拓扑结构,这是非常耗内存和CPU。

把文件和目录的元数据信息持久化地存储到fsimage文件中,每次启动时从中将元数据加载到内存中构建目录结构树
之后的操作记录在edits log中,定期将edits与fsimage合并刷到fsimage中

7、NameNode文件结构

最新格式化的NameNode会创建以下目录结构:
  $ {dfs.name.dir}                    //dfs.name.dir是一个目录列表,是每个目录的镜像
  $ {dfs.name.dir}/current/VERSION     //Java属性文件,其中包含运行HDFS的版本信息
  $ {dfs.name.dir}/current/edits
  $ {dfs.name.dir}/current/fsimage
  $ {dfs.name.dir}/current/fstime

VERSION文件包含的内容:
      #Wed Mar 23 16:03:27  CST 2017
      namespaceID=1064465394    //文件系统的统一标识符,在文件系统第一次被格式化时创建
                                这个标识符也要求各DataNode节点和NameNode保持一致
                                NameNode会使用此标识符识别新的DataNode
                                DataNode只有在向NameNode注册后才会获得此namespaceID。

      cTime=0                  //标记了NameNode存储空间创建的时间
                                当文件系统被更新,它就会更新到一个新的时间戳。

      storageType=NAME_NODE     //用于指出此存储目录包含一个NameNode的数据结构
                                在DataNode中空属性值为DATA_NODE

      layoutVersion=-18         //layoutVersion是一个负的整数,定义了HDFS持久化数据结果的版本
                                每次HDFS的布局发生改变,该版本号就会递减(比如-18之后是-19)
                                在这种情况下,HDFS就需要更新升级,各节点的版本号要保持一致

NameNode的存储目录

包括edits、fsimage、fstime三个文件(二进制文件)。可以通过HadoopWritable对象进行反序列化。
hdfs的命名空间存储在namenode的内存中,EditLog/FsImage存储在namenode本地的文件系统中
    EditLog事务日志
        记录发生在文件系统元数据上的所有变化。
        编辑日志会在每次成功操作之后,成功代码尚未返回给客户端之前进行刷新和同步。
        对于要写入多个目录的操作,写入流要刷新和同步到所有的副本
        这就保证了操作不会因故障而丢失数据。

        比如:
        在文件系统中创建一个文件,namenode就会在EditLog中插入一条记录标记一下。
        同样的,修改一个文件的副本因子同样会在触发EditLog中插入一条记录。

    FsImage文件
        是文件系统元数据的持久性检查点checkpoint。
        存放整个系统的命名空间,包括块和文件的映射表,文件系统属性
        一个fsimage文件包含以序列化格式存储的文件系统目录和文件索引
        每个索引表示一个文件或目录的元数据信息,以及文件的副本数、修改和访问时间等信息。

        和编辑日志不同,它不会在每个文件系统的写操作后都进行更新
        因为写出fsimage文件会非常慢(fsimage可能增长到GB大小)。这种设计并不会影响系统的恢复力
        如果NameNode失败,可以通过读出磁盘中fsimage文件加载到内存中来进行重建恢复
        然后重新执行编辑日志中的操作。事实上,这也正是NameNode启动时要做的事情。