# 4.1 元数据管理

1.元数据管理概述

HDFS 元数据，按类型分，主要包括以下几个部分: 

- 1、文件、目录自身的属性信息，例如文件名，目录名，修改信息等。

- 2、文件记录的信息的存储相关的信息，例如存储块信息，分块情况，副本个数等。 

- 3、记录 HDFS 的 Datanode 的信息，用于 DataNode 的管理。

按形式分为内存元数据和元数据文件两种，分别存在内存和磁盘上

HDFS 磁盘上元数据文件分为两类，用于持久化存储:

fsimage 镜像文件：

是元数据的一个持久化的检查点，包含 Hadoop 文件系统中的所有目录和文件元数据信息，但不包含文件块位置的信息。文件块位置信息只存储在内存中，是在 datanode 加入集群的时候，namenode 询问 datanode 得到的，并且间断的更新。 

Edits 编辑日志：存放的是 Hadoop 文件系统的所有更改操作(文件创建，删除或修改) 的日志，文件系统客户端执行的更改操作首先会被记录到 edits 文件中。

fsimage 和 edits 文件都是经过序列化的，在 NameNode 启动的时候，它会将 fsimage 文件中的内容加载到内存中，之后再执行 edits 文件中的各项操作，使得内存中的元数据和实际的同步，存在内存中的元数据支持客户端的读操作，也是最完整的元数据。

当客户端对 HDFS 中的文件进行新增或者修改操作，操作记录首先被记入 edits 日志文 件中，当客户端操作成功后，相应的元数据会更新到内存元数据中。因为 fsimage 文件一般 都很大(GB 级别的很常见)，如果所有的更新操作都往 fsimage 文件中添加，这样会导致系 统运行的十分缓慢。 

HDFS 这种设计实现着手于:一是内存中数据更新、查询快，极大缩短了操作响应时间; 二是内存中元数据丢失风险颇高(断电等)，因此辅佐元数据镜像文件(fsimage)+编辑日志文件(edits)的备份机制进行确保元数据的安全。 

NameNode 维护整个文件系统元数据。因此，元数据的准确管理，影响着 HDFS 供文件存储服务的能力。 

2.元数据目录相关文件

在 Hadoop 的 HDFS 首次部署好配置文件之后，并不能马上启动使用，而是先要对文件系 统进行格式化。需要在 NameNode(NN)节点上进行如下的操作:

$HADOOP_HOME/bin/hdfs namenode –format

在这里要注意两个概念，一个是文件系统，此时的文件系统在物理上还不存在;二就是 此处的格式化并不是指传统意义上的本地磁盘格式化，而是一些清除与准备工作。

格式化完成之后，将会在$dfs.namenode.name.dir/current目录下创建如下的文件结构，这个目录也正是 namenode 元数据相关的文件目录：

![img](img/zq1.png) 

 

其中的 dfs.namenode.name.dir 是在 hdfs-site.xml 文件中配置的，默认值如下:

![img](img/zq2.png) 

dfs.namenode.name.dir 属性可以配置多个目录，各个目录存储的文件结构和内容都完 全一样，相当于备份，这样做的好处是当其中一个目录损坏了，也不会影响到 Hadoop 的元数据，特别是当其中一个目录是 NFS(网络文件系统 Network File System，NFS)之上，即 使你这台机器损坏了，元数据也得到保存。

下面对$dfs.namenode.name.dir/current/目录下的文件进行解释。

VERSION 

namespaceID=934548976 

clusterID=CID-cdff7d73-93cd-4783-9399-0a22e6dce196 

cTime=0

storageType=NAME_NODE 

blockpoolID=BP-893790215-192.168.24.72-1383809616115 

layoutVersion=-47 

namespaceID/clusterID/blockpoolID 这些都是 HDFS 集群的唯一标识符。标识符被用来防止 DataNodes 意外注册到另一个集群中的 namenode 上。这些标识在联邦(federation) 部署中特别重要。联邦模式下，会有多个 NameNode 独立工作。每个的 NameNode 提供唯一的 命名空间(namespaceID)，并管理一组唯一的文件块池(blockpoolID)。clusterID 将整个集群结合在一起作为单个逻辑单元，在集群中的所有节点上都是一样的。 

storageType：说明这个文件存储的是什么进程的数据结构信息(如果是 DataNode，storageType=DATA_NODE); 

cTime：NameNode 存储系统创建时间，首次格式化文件系统这个属性是 0，当文件系统升级之后，该值会更新到升级之后的时间戳;

layoutVersion：表示 HDFS 永久性数据结构的版本信息，是一个负整数。

补充说明: 

格式化集群的时候，可以指定集群的 cluster_id，但是不能与环境中其他集群有冲突。 如果没有提供 cluster_id，则会自动生成一个唯一的 ClusterID。 

$HADOOP_HOME/bin/hdfs namenode -format -clusterId <cluster_id> 

seen_txid 

dfs.namenode.name.dir/current/seen_txid 非常重要，是存放 transactionId 的文件，format 之后是 0， 它代表的是 namenode 里面的 edits_*文件的尾数，namenode 重启的时候，会按照 seen_txid 的数字，循序从头跑 edits_0000001~到 seen_txid 的数字。所以 当你的 hdfs 发生异常重启的时候，一定要比对 seen_txid 内的数字是不是你 edits 最后的尾数。

Fsimage & edits 

$dfs.namenode.name.dir/current 目录下在 format 的同时也会生成 fsimage 和 edits 文件，及其对应的 md5 校验文件。 

3.secondary namenode 

![img](img/zq3.png) 

NameNode 职责是管理元数据信息，DataNode 的职责是负责数据具体存储，那么 SecondaryNameNode 的作用是什么?对很多初学者来说是非常迷惑的。它为什么会出现在 HDFS 中。从它的名字上看，它给人的感觉就像是 NameNode 的备份。但它实际上却不是。 

大家猜想一下，当 HDFS 集群运行一段时间后，就会出现下面一些问题: edit logs 文件会变的很大，怎么去管理这个文件是一个挑战。 NameNode重启会花费很长时间，因为有很多改动要合并到fsimage文件上。如果NameNode挂掉了，那就丢失了一些改动。因为此时的fsimage文件非常旧。因此为了克服这个问题，我们需要一个易于管理的机制来帮助我们减小edit logs文件的大小和得到一个最新的fsimage文件，这样也会减小在 NameNode上的压力。这跟Windows的恢复点是非常像的，Windows的恢复点机制允许我们对OS进行快照，这样当系统发生问题时，我们能够回滚到最新的一次恢复点上。SecondaryNameNode就是来帮助解决上述问题的，它的职责是合并NameNode的edit logs到fsimage文件中。

4.Checkpoint 

每达到触发条件，会由 secondary namenode 将 namenode 上积累的所有 edits 和一个 最新的 fsimage 下载到本地，并加载到内存进行 merge（这个过程称为checkpoint），如下图所示：

![img](img/zq4.png) 

4.1. Checkpoint 详细步骤

- NameNode 管理着元数据信息，其中有两类持久化元数据文件:edits操作日志文件和 fsimage 元数据镜像文件。新的操作日志不会立即与 fsimage 进行合并，也不会刷到 NameNode 的内存中，而是会先写到 edits 中(因为合并需要消耗大量的资源)，操作成功之后更新至内存。
- 有 dfs.namenode.checkpoint.period 和 dfs.namenode.checkpoint.txns 两个配置，只要达到这两个条件任何一个，secondarynamenode 就会执行 checkpoint 的操作。
- 当触发 checkpoint 操作时，NameNode 会生成一个新的 edits 即上图中的 edits.new 文 件，同时SecondaryNameNode 会将 edits 文件和 fsimage 复制到本地(HTTP GET 方式)。
- secondarynamenode将下载下来的fsimage载入到内存，然后一条一条地执行 edits 文 件中的各项更新操作，使得内存中的 fsimage 保存最新，这个过程就是edits和fsimage文件合并，生成一个新的 fsimage 文件即上图中的 Fsimage.ckpt 文件。
- secondarynamenode 将新生成的 Fsimage.ckpt 文件复制到 NameNode 节点。
- 在 NameNode 节点的 edits.new 文件和 Fsimage.ckpt 文件会替换掉原来的 edits 文件 和 fsimage 文件，至此刚好是一个轮回，即在 NameNode 中又是 edits 和 fsimage 文件。
- 等待下一次 checkpoint 触发 SecondaryNameNode 进行工作，一直这样循环操作。

4.2. Checkpoint 触发条件 

Checkpoint 操作受两个参数控制，可以通过 core-site.xml 进行配置：

```
<property><name> dfs.namenode.checkpoint.period</name> 

	<value>3600</value>
	<description>
	两次连续的 checkpoint 之间的时间间隔。默认 1 小时
	</description> 
</property>
```

```
<property>

	<name>dfs.namenode.checkpoint.txns</name> <value>1000000</value>
	<description> 

	最大的没有执行 checkpoint 事务的数量，满足将强制执行紧急 checkpoint，即使尚未达到检查点周期。默认设置为 100 万。 
	</description> 
</property> 
```

从上面的描述我们可以看出，SecondaryNamenode 根本就不是 Namenode 的一个热备， 其只是将 fsimage 和 edits 合并。其拥有的 fsimage 不是最新的，因为在他从 NameNode 下 载 fsimage 和 edits 文件时候，新的更新操作已经写到 edit.new 文件中去了。而这些更新 在 SecondaryNamenode 是没有同步到的!当然，如果 NameNode 中的 fsimage 真的出问题了， 还是可以用 SecondaryNamenode 中的 fsimage 替换一下 NameNode 上的 fsimage，虽然已经 不是最新的 fsimage，但是我们可以将损失减小到最少!