5. HDFS--NameNode和SecondaryNameNode

NameNode和SecondaryNameNode

1. NN和2NN工作机制

思考:NameNode中的元数据是存储在哪里的?

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

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

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

在这里插入图片描述

第一阶段:NameNode启动
  1. 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
  2. 客户端对元数据进行增删改的请求。
  3. NameNode记录操作日志,更新滚动日志。
  4. NameNode在内存中对数据进行增删改。
第二阶段:Secondary NameNode工作
  1. Secondary NameNode询问NameNode是否需要CheckPoint。直接带回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。
NN和2NN工作机制详解:

如果还不清楚,可以看一下下面这些内容:

  • Fsimage:NameNode内存中元数据序列化后形成的文件。
  • Edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。
  1. NameNode启动时,先滚动Edits并生成一个空的edits.inprogress,然后加载Edits和Fsimage到内存中,此时NameNode内存就持有最新的元数据信息。Client开始对NameNode发送元数据的增删改的请求,这些请求的操作首先会被记录到edits.inprogress中(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息),如果此时NameNode挂掉,重启后会从Edits中读取元数据的信息。然后,NameNode会在内存中执行元数据的增删改的操作。

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

  3. 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中。

2. Fsimage和Edits解析

NameNode被格式化后的在/opt/module/hadoop-2.7.2/data/tmp/dfs/name/current中产生如下文件:

在这里插入图片描述

  1. Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
  2. Edits文件:存放HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中。
  3. seen_txid文件保存的是一个数字,就是最后一个edits_的数字
  4. 每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。
oiv查看Fsimage文件
#hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
hdfs oiv -p XML -i fsimage_0000000000000000000 -o /opt/module/hadoop-2.7.2/fsimage.xml

将显示的xml文件内容拷贝到idea中创建的xml文件中,并格式化ctrl + alt + L;

<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>atguigu: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上报数据块信息,并间隔一段时间后再次上报。

oev查看Edits文件
#hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
hdfs oev -p XML -i edits_inprogress_0000000000000000003 -o /opt/module/hadoop-2.7.2/edits.xml1
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>1</TXID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_END_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>2</TXID>
    </DATA>
  </RECORD>
</EDITS>

执行了一下操作之后,再次查看的结果如下:

hadoop fs -mkdir -p /user/atguigu/input
hadoop fs -put ./zaiyiqi.txt  /user/atguigu/input
hdfs oev -p XML -i edits_inprogress_0000000000000000003 -o /opt/module/hadoop-2.7.2/edits.xml1
<?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>
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>4</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16386</INODEID>
      <PATH>/user</PATH>
      <TIMESTAMP>1594046027348</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>atguigu</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>5</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16387</INODEID>
      <PATH>/user/atguigu</PATH>
      <TIMESTAMP>1594046027364</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>atguigu</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_MKDIR</OPCODE>
    <DATA>
      <TXID>6</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16388</INODEID>
      <PATH>/user/atguigu/input</PATH>
      <TIMESTAMP>1594046027364</TIMESTAMP>
      <PERMISSION_STATUS>
        <USERNAME>atguigu</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>493</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>7</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16389</INODEID>
      <PATH>/user/atguigu/input/zaiyiqi.txt._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1594046058186</MTIME>
      <ATIME>1594046058186</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME>DFSClient_NONMAPREDUCE_-441620276_1</CLIENT_NAME>
      <CLIENT_MACHINE>192.168.68.136</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>atguigu</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <RPC_CLIENTID>d364925b-103b-42fb-be3e-7cc7f509192f</RPC_CLIENTID>
      <RPC_CALLID>3</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>8</TXID>
      <BLOCK_ID>1073741825</BLOCK_ID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
    <DATA>
      <TXID>9</TXID>
      <GENSTAMPV2>1001</GENSTAMPV2>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD_BLOCK</OPCODE>
    <DATA>
      <TXID>10</TXID>
      <PATH>/user/atguigu/input/zaiyiqi.txt._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>11</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/user/atguigu/input/zaiyiqi.txt._COPYING_</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1594046058954</MTIME>
      <ATIME>1594046058186</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME></CLIENT_NAME>
      <CLIENT_MACHINE></CLIENT_MACHINE>
      <OVERWRITE>false</OVERWRITE>
      <BLOCK>
        <BLOCK_ID>1073741825</BLOCK_ID>
        <NUM_BYTES>52</NUM_BYTES>
        <GENSTAMP>1001</GENSTAMP>
      </BLOCK>
      <PERMISSION_STATUS>
        <USERNAME>atguigu</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_RENAME_OLD</OPCODE>
    <DATA>
      <TXID>12</TXID>
      <LENGTH>0</LENGTH>
      <SRC>/user/atguigu/input/zaiyiqi.txt._COPYING_</SRC>
      <DST>/user/atguigu/input/zaiyiqi.txt</DST>
      <TIMESTAMP>1594046058968</TIMESTAMP>
      <RPC_CLIENTID>d364925b-103b-42fb-be3e-7cc7f509192f</RPC_CLIENTID>
      <RPC_CALLID>8</RPC_CALLID>
    </DATA>
  </RECORD>
</EDITS>

那么NameNode如何确定下次开机启动的时候合并哪些Edits?

CheckPoint时间设置

通常情况下,SecondaryNameNode每隔一小时执行一次。

可以配置hdfs-default.xml来进行设置CheckPoint时间,默认是3600秒;

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
</property>

一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次

<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 >
3. NameNode故障处理

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

方法一

将SecondaryNameNode中数据拷贝到NameNode存储数据的目录;

#kill -9 NameNode进程
kill -9 11390
#删除NameNode存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)
rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
#拷贝SecondaryNameNode中数据到原NameNode存储数据目录
scp -r atguigu@hadoop102:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary/* /opt/module/hadoop-2.7.2/data/tmp/dfs/name/
#重新启动NameNode
sbin/hadoop-daemon.sh start namenode
方法二(推荐使用)

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

需要提前配置hdfs-site.xml

<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>

具体的操作:

#kill -9 NameNode进程
kill -9 11390
#删除NameNode存储的数据(/opt/module/hadoop-2.7.2/data/tmp/dfs/name)
rm -rf /opt/module/hadoop-2.7.2/data/tmp/dfs/name/*
#如果SecondaryNameNode不和NameNode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件
scp -r atguigu@hadoop102:/opt/module/hadoop-2.7.2/data/tmp/dfs/namesecondary /opt/module/hadoop-2.7.2/data/tmp/dfs

#导入检查点数据(等待一会ctrl+c结束掉)
bin/hdfs namenode -importCheckpoint
#启动NameNode
sbin/hadoop-daemon.sh start namenode
4. NameNode多目录配置

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

具体配置如下

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>
#停止集群,删除data和logs中所有数据。
rm -rf data/ logs/
#格式化集群并启动。
bin/hdfs namenode –format
sbin/start-dfs.sh
#进入到目录中就可以看到结果

hadoop-env.sh是Hadoop的环境变量配置文件,用于设置Hadoop运行环境的各种参数。其中主要包含以下参数: 1. HADOOP_HEAPSIZE:设定Hadoop所使用的Java虚拟机的堆内存大小。 2. HADOOP_OPTS:用于设置Hadoop运行时的Java虚拟机参数。 3. HADOOP_NAMENODE_OPTS:用于设置NameNode节点的Java虚拟机参数。 4. HADOOP_DATANODE_OPTS:用于设置DataNode节点的Java虚拟机参数。 5. HADOOP_SECONDARYNAMENODE_OPTS:用于设置SecondaryNameNode节点的Java虚拟机参数。 6. HADOOP_JOB_HISTORYSERVER_OPTS:用于设置JobHistoryServer节点的Java虚拟机参数。 core-site.xml是Hadoop的核心配置文件,用于配置Hadoop的核心参数。其中主要包含以下参数: 1. fs.defaultFS:指定Hadoop的文件系统的默认URL。 2. hadoop.tmp.dir:指定Hadoop的临时文件存储目录。 3. io.file.buffer.size:指定Hadoop读写文件时的缓冲区大小。 4. hadoop.proxyuser.*.hosts和hadoop.proxyuser.*.groups:用于配置代理用户的主机和组。 hdfs-site.xml是Hadoop分布式文件系统(HDFS)的配置文件,用于配置HDFS的参数。其中主要包含以下参数: 1. dfs.replication:指定HDFS中数据的副本数。 2. dfs.namenode.name.dir和dfs.datanode.data.dir:分别指定NameNode和DataNode存储数据的目录。 3. dfs.permissions.enabled:指定是否启用HDFS的权限控制。 4. dfs.blocksize:指定HDFS中数据块的大小。 yarn-site.xml是Hadoop的资源管理器(YARN)的配置文件,用于配置YARN的参数。其中主要包含以下参数: 1. yarn.nodemanager.aux-services和yarn.nodemanager.aux-services.mapreduce.shuffle.class:用于配置NodeManager上的附属服务,如MapReduce的shuffle服务。 2. yarn.resourcemanager.hostname:指定ResourceManager的主机名。 3. yarn.scheduler.minimum-allocation-mb和yarn.scheduler.maximum-allocation-mb:分别指定YARN的最小和最大资源分配单元的内存大小。 4. yarn.nodemanager.resource.memory-mb:指定NodeManager的可用内存大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值