Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

NameNode和SecondaryNameNode

NN和2NN的工作机制

NameNode 中的元数据是存储:

首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage

这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,就会产生数据丢失。因此,引入 Edits 文件(只进行追加操作,效率很高)每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到 Edits 中。这样,一旦 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合成元数据。

但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,如果这个操作由 NameNode 节点完成,又会效率过低。因此,引入一个新的节点 SecondaryNamenode,专门用于 FsImage 和 Edits 的合并。

NN和2NN的工作机制如下:

Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

  1. 第一阶段: NameNode 启动
    (1)第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。

(2)客户端对元数据进行增删改的请求。

(3)NameNode 记录操作日志,更新滚动日志(先更新日志,再进行内存数据的修改)。

(4)NameNode 在内存中对数据进行增删改。

即最新edits+最新fsimage=内存中的数据

  1. 第二阶段:Secondary NameNode 工作
    (1)Secondary NameNode 询问 NameNode 是否需要 CheckPoint,即进行Edits和fsImage的合并(执行检查点的条件:定时时间到了,默认1小时;或Edits中数据满了,默认1百万条)。直接带回 NameNode是否检查结果。

(2)Secondary NameNode 请求执行 CheckPoint。

(3)NameNode 滚动正在写的 Edits 日志。

(4)将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。

(5)Secondary NameNode 加载编辑日志和镜像文件到内存,并合并。

(6)生成新的镜像文件 fsimage.chkpoint。

(7)拷贝 fsimage.chkpoint 到 NameNode。

(8)NameNode 将 fsimage.chkpoint 重新命名成 fsimage。

详解如下:

Fsimage:NameNode 内存中元数据序列化后形成的文件。

Edits:记录客户端更新元数据信息的每一步操作(可通过 Edits 运算出元数据)。

NameNode 启动时,先滚动 Edits 并生成一个空的 edits.inprogress,然后加载 Edits 和 Fsimage到内存中,此时 NameNode 内存就持有最新的元数据信息。Client 开始对 NameNode 发送元数据的增删改的请求,这些请求的操作首先会被记录到 edits.inprogress 中(查询元数据的操作不会被记录在 Edits 中,因为查询操作不会更改元数据信息),如果此时 NameNode挂掉,重启后会从 Edits 中读取元数据的信息。然后,NameNode 会在内存中执行元数据的增删改的操作。

由于 Edits 中记录的操作会越来越多, Edits 文件会越来越大,导致 NameNode 在启动加载Edits 时会很慢,所以需要对 Edits 和 Fsimage 进行合并(所谓合并,就是将 Edits 和 Fsimage加 载 到 内 存 中 , 照 着 Edits 中 的 操 作 一 步 步 执 行 , 最 终 形 成 新 的 Fsimage ) 。SecondaryNameNode 的作用就是帮助 NameNode 进行 Edits 和 Fsimage 的合并工作。

SecondaryNameNode 首先会询问 NameNode 是否需要 CheckPoint(触发 CheckPoint 需要满足两个条件中的任意一个,定时时间到和 Edits 中数据写满了)。直接带回 NameNode是否检查结果。SecondaryNameNode 执行 CheckPoint 操作,首先会让 NameNode 滚动 Edits并生成一个空的 edits.inprogress,滚动 Edits 的目的是给 Edits 打个标记,以后所有新的操作都写入 edits.inprogress,其他未合并的 Edits 和 Fsimage 会拷贝到 SecondaryNameNode的本地,然后将拷贝的 Edits 和 Fsimage 加载到内存中进行合并,生成 fsimage.chkpoint,然后将 fsimage.chkpoint 拷贝给 NameNode,重命名为 Fsimage 后替换掉原来的 Fsimage。NameNode 在启动时就只需要加载之前未合并的 Edits 和 Fsimage 即可,因为合并过的Edits 中的元数据信息已经被记录在 Fsimage中。

Fsimage和Edits解析

NN的文件存放路径在:data/tmp/dfs/name/current

2NN的在:data/tmp/dfs/namesecondary/current

NN的目录下存放内容如下:

Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

2NN的如下:
Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

不同之处在于NN多了edits_inprogress文件表示当前记录客户端操作的文件以及seen_txid表示当前edits文件号

直接读取edits操作日志文件和fsimage镜像文件是乱码的,可以通过以下命令进行查看

### 转换fsimage文件,-p表示转换成什么格式,-i表示要查看的文件名
hdfs oiv -p XML -i fsimage文件 -o 转换之后的文件名

### 转换edits文件
hdfs oev -p XML -i edits文件 -o 转换之后的文件名

为了更好的查看两个文件的内容,将集群初始化。

初始化集群时,要先将集群关闭,然后删除data和logs目录,再到namenode服务器执行初始化nn的操作;最后开启集群。

初始化情况下默认是没有edits文件的,只有编号为0的fsimage文件,待集群启动之后才会生成edits文件。

创建一个目录/sanguo/wei,然后上传一个文件caocao到该目录下。

最新的fsiamge内容如下,并没有看到与创建目录和上传文件有关信息,说明此时还没有进行edits和fsimage的合并

<?xml version="1.0"?>
<fsimage>
    <NameSection>
        <genstampV1>1000</genstampV1>
        <genstampV2>1000</genstampV2>
        <genstampV1Limit>0</genstampV1Limit>
        <lastAllocatedBlockId>1073741824</lastAllocatedBlockId>
        <txid>0</txid>
    </NameSection>
    <INodeSection>
        <lastInodeId>16385</lastInodeId>
        <inode>
            <id>16385</id>
            <type>DIRECTORY</type>
            <name></name>
            <mtime>0</mtime>
            <permission>bd:supergroup:rwxr-xr-x</permission>
            <nsquota>9223372036854775807</nsquota>
            <dsquota>-1</dsquota>
        </inode>
    </INodeSection>
    <INodeReferenceSection></INodeReferenceSection>
    <SnapshotSection>
        <snapshotCounter>0</snapshotCounter>
    </SnapshotSection>
    <INodeDirectorySection></INodeDirectorySection>
    <FileUnderConstructionSection></FileUnderConstructionSection>
    <SnapshotDiffSection>
        <diff>
            <inodeid>16385</inodeid>
        </diff>
    </SnapshotDiffSection>
    <SecretManagerSection>
        <currentId>0</currentId>
        <tokenSequenceNumber>0</tokenSequenceNumber>
    </SecretManagerSection>
    <CacheManagerSection>
        <nextDirectiveId>1</nextDirectiveId>
    </CacheManagerSection>
</fsimage>

可以看出,Fsimage 中没有记录块所对应 DataNode,因为在集群启动后,要求 DataNode 上报数据块信息,并间隔一段时间后再次上报。防止静态记录的方式因为DN挂掉之后导致意外的问题,因此需要DN定时动态上报数据块信息。

最新的edits文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  <RECORD>
    <!-- 日志开始 -->
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>3</TXID>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 创建/sanguo目录 -->
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>4</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16386</INODEID>
      <PATH>/sanguo</PATH>
      <TIMESTAMP>1625023339562</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>bd</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 创建/sanguo/wei目录 -->
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>5</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16387</INODEID>
      <PATH>/sanguo/wei</PATH>
      <TIMESTAMP>1625023339571</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>bd</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 上传文件,此时名称还是xxx.COPYING -->
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>6</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16388</INODEID>
      <PATH>/sanguo/wei/caocao._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1625023365316</MTIME>
      <ATIME>1625023365316</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME>DFSClient_NONMAPREDUCE_-245424670_1</CLIENT_NAME>
      <CLIENT_MACHINE>10.10.10.113</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>bd</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <RPC_CLIENTID>f1e13e50-bcba-45fc-b6b1-3d56321921af</RPC_CLIENTID>
      <RPC_CALLID>3</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 分配块id -->
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>7</TXID>
      <BLOCK_ID>1073741825</BLOCK_ID>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 生成时间戳 -->
    <OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
    <DATA>
      <TXID>8</TXID>
      <GENSTAMPV2>1001</GENSTAMPV2>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 添加块信息 -->
    <OPCODE>OP_ADD_BLOCK</OPCODE>
    <DATA>
      <TXID>9</TXID>
      <PATH>/sanguo/wei/caocao._COPYING_</PATH>
      <BLOCK>
        <BLOCK_ID>1073741825</BLOCK_ID>
        <NUM_BYTES>0</NUM_BYTES>
        <GENSTAMP>1001</GENSTAMP>
      </BLOCK>
      <RPC_CLIENTID></RPC_CLIENTID>
      <RPC_CALLID>-2</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 操作结束 -->
    <OPCODE>OP_CLOSE</OPCODE>
    <DATA>
      <TXID>10</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/sanguo/wei/caocao._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1625023366262</MTIME>
      <ATIME>1625023365316</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME></CLIENT_NAME>
      <CLIENT_MACHINE></CLIENT_MACHINE>
      <OVERWRITE>false</OVERWRITE>
      <BLOCK>
        <BLOCK_ID>1073741825</BLOCK_ID>
        <NUM_BYTES>15</NUM_BYTES>
        <GENSTAMP>1001</GENSTAMP>
      </BLOCK>
      <PERMISSION_STATUS>
        <USERNAME>bd</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <!-- 重命名COPYING文件 -->
    <OPCODE>OP_RENAME_OLD</OPCODE>
    <DATA>
      <TXID>11</TXID>
      <LENGTH>0</LENGTH>
      <SRC>/sanguo/wei/caocao._COPYING_</SRC>
      <DST>/sanguo/wei/caocao</DST>
      <TIMESTAMP>1625023366270</TIMESTAMP>
      <RPC_CLIENTID>f1e13e50-bcba-45fc-b6b1-3d56321921af</RPC_CLIENTID>
      <RPC_CALLID>9</RPC_CALLID>
    </DATA>
  </RECORD>
</EDITS>

NN通过seen.txid能够确定下次合并的Edits文件内容。

CheckPoint时间设置

默认情况下,2NN每隔1小时执行一次

<!-- hdfs-default.xml -->
<property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>3600</value>
</property>

默认情况下,一分钟检查一次操作次数,当操作次数达到 1 百万时,2NN 执行一次。

<!-- hdfs-default.xml -->
<property>
    <name>dfs.namenode.checkpoint.txns</name>
    <value>1000000</value>
    <description>操作动作次数</description>
</property>
<property>
    <name>dfs.namenode.checkpoint.check.period</name>
    <value>60</value>
    <description> 1 分钟检查一次操作次数</description>
</property >

可以通过hdfs-site.xml进行配置

NameNode故障处理

NameNode 故障后,可以采用如下两种方法恢复数据。

方法一:将 SecondaryNameNode 中数据拷贝到 NameNode 存储数据的目录;

模拟步骤:

1、kill -9 NameNode 进程

2、删除 NameNode 存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)

rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*

3、拷贝 SecondaryNameNode 中数据到原 NameNode 存储数据目录

scp -r bd@hadoop115:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary/* /opt/module/hadoop-2.7.2/data/tmp/dfs/name/

4、重新启动 NameNode

sbin/hadoop-daemon.sh start namenode

方 法 二 : 使 用 -importCheckpoint 选 项 启 动 NameNode 守 护 进 程 , 从 而 将SecondaryNameNode 中数据拷贝到 NameNode 目录中。

模拟步骤:

1、修改 hdfs-site.xml 中的,修改完成之后要使用之前的xsync命令进行配置文件的分发,更新其他服务器上的配置文件

<property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>120</value>
</property>
<property>
    <name>dfs.namenode.name.dir</name>
    <value>/opt/module/hadoop-2.7.2/data/tmp/dfs/name</value>
</property>

2、kill -9 NameNode 进程

3、删除 NameNode 存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)

rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*

4、如果 SecondaryNameNode 不和 NameNode 在一个主机节点上,需要将 SecondaryNameNode 存储数据的目录拷贝到 NameNode 存储数据的平级目录,并删除 in_use.lock 文件

scp -r bd@hadoop115:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary /opt/module/hadoop-2.7.2/data/tmp/dfs

## 删除使用锁文件
rm -rf in_use.lock

## ls /opt/module/hadoop-2.7.2/data/tmp/dfs结果如下:
data name namesecondary

5、导入检查点数据(等待一会 ctrl+c 结束掉)

bin/hdfs namenode -importCheckpoint

6、启动 NameNode

sbin/hadoop-daemon.sh start namenode

集群的安全模式

Hadoop-HDFS的NameNode和SecondaryNameNode介绍及原理

集群处于安全模式,不能执行重要操作(写操作,如上传文件会失败)。集群启动完成后,自动退出安全模式。

## 安全模式相关命令
### 查看安全模式状态
bin/hdfs dfsadmin -safemode get

### 进入安全模式状态
bin/hdfs dfsadmin -safemode enter

### 离开安全模式状态
bin/hdfs dfsadmin -safemode leave

### 等待安全模式状态
bin/hdfs dfsadmin -safemode wait

等待安全模式状态案例如下:

1、查看当前模式

hdfs dfsadmin -safemode get
## 结果如下:
Safe mode is OFF

2、先进入安全模式

bin/hdfs dfsadmin -safemode enter

3、创建并执行下面的脚本

#!/bin/bash

## 等待安全模式
hdfs dfsadmin -safemode wait

## 执行上传操作
hdfs dfs -put /opt/module/hadoop-2.7.2/README.txt /

执行这个脚本的时候会因为等待安全模式导致一直阻塞在那里。
4、退出安全模式

bin/hdfs dfsadmin -safemode leave

此时可以看到之前阻塞在那里的脚本执行完成了,并且打出了Safe mode is OFF信息,文件也被上传成功了。

NN多目录配置

NameNode 的本地目录可以配置成多个,且每个目录存放内容相同,可以增加可靠性

具体配置如下:

1、先初始化所有的集群:关闭集群、删除logs和data

2、在hdfs-site.xml中增加以下内容,并将配置文件分发到各个服务器上

<property>
    <name>dfs.namenode.name.dir</name>
    <value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2</value>
</property>

3、格式化NN(hdfs namenode -format),这里要等配置完成之后再格式化,因为格式化的时候就会读取配置文件去创建NN的目录了

4、启动集群(start-dfs.sh)

5、上传一个文件

hadoop fs -put caocao /caocao

6、查看两个namex目录下的内容,发现两个内容均相同。

上一篇:Hadoop的HA原理


下一篇:第九章 HDFS概述