NameNode 中的元数据是存储:
首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,就会产生数据丢失。因此,引入 Edits 文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到 Edits 中。这样,一旦 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合成元数据。
但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,如果这个操作由 NameNode 节点完成,又会效率过低。因此,引入一个新的节点 SecondaryNamenode,专门用于 FsImage 和 Edits 的合并。
NN和2NN的工作机制如下:
(2)客户端对元数据进行增删改的请求。
(3)NameNode 记录操作日志,更新滚动日志(先更新日志,再进行内存数据的修改)。
(4)NameNode 在内存中对数据进行增删改。
即最新edits+最新fsimage=内存中的数据
(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中。
NN的文件存放路径在:data/tmp/dfs/name/current
2NN的在:data/tmp/dfs/namesecondary/current
NN的目录下存放内容如下:
不同之处在于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的合并
<fsimage>
<NameSection>
<genstampV1>1000genstampV1>
<genstampV2>1000genstampV2>
<genstampV1Limit>0genstampV1Limit>
<lastAllocatedBlockId>1073741824lastAllocatedBlockId>
<txid>0txid>
NameSection>
<INodeSection>
<lastInodeId>16385lastInodeId>
<inode>
<id>16385id>
<type>DIRECTORYtype>
<name>name>
<mtime>0mtime>
<permission>bd:supergroup:rwxr-xr-xpermission>
<nsquota>9223372036854775807nsquota>
<dsquota>-1dsquota>
inode>
INodeSection>
<INodeReferenceSection>INodeReferenceSection>
<SnapshotSection>
<snapshotCounter>0snapshotCounter>
SnapshotSection>
<INodeDirectorySection>INodeDirectorySection>
<FileUnderConstructionSection>FileUnderConstructionSection>
<SnapshotDiffSection>
<diff>
<inodeid>16385inodeid>
diff>
SnapshotDiffSection>
<SecretManagerSection>
<currentId>0currentId>
<tokenSequenceNumber>0tokenSequenceNumber>
SecretManagerSection>
<CacheManagerSection>
<nextDirectiveId>1nextDirectiveId>
CacheManagerSection>
fsimage>
可以看出,Fsimage 中没有记录块所对应 DataNode,因为在集群启动后,要求 DataNode 上报数据块信息,并间隔一段时间后再次上报。防止静态记录的方式因为DN挂掉之后导致意外的问题,因此需要DN定时动态上报数据块信息。
最新的edits文件内容如下:
<EDITS>
<EDITS_VERSION>-63EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENTOPCODE>
<DATA>
<TXID>3TXID>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_MKDIROPCODE>
<DATA>
<TXID>4TXID>
<LENGTH>0LENGTH>
<INODEID>16386INODEID>
<PATH>/sanguoPATH>
<TIMESTAMP>1625023339562TIMESTAMP>
<PERMISSION_STATUS>
<USERNAME>bdUSERNAME>
<GROUPNAME>supergroupGROUPNAME>
<MODE>493MODE>
PERMISSION_STATUS>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_MKDIROPCODE>
<DATA>
<TXID>5TXID>
<LENGTH>0LENGTH>
<INODEID>16387INODEID>
<PATH>/sanguo/weiPATH>
<TIMESTAMP>1625023339571TIMESTAMP>
<PERMISSION_STATUS>
<USERNAME>bdUSERNAME>
<GROUPNAME>supergroupGROUPNAME>
<MODE>493MODE>
PERMISSION_STATUS>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_ADDOPCODE>
<DATA>
<TXID>6TXID>
<LENGTH>0LENGTH>
<INODEID>16388INODEID>
<PATH>/sanguo/wei/caocao._COPYING_PATH>
<REPLICATION>3REPLICATION>
<MTIME>1625023365316MTIME>
<ATIME>1625023365316ATIME>
<BLOCKSIZE>134217728BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-245424670_1CLIENT_NAME>
<CLIENT_MACHINE>10.10.10.113CLIENT_MACHINE>
<OVERWRITE>trueOVERWRITE>
<PERMISSION_STATUS>
<USERNAME>bdUSERNAME>
<GROUPNAME>supergroupGROUPNAME>
<MODE>420MODE>
PERMISSION_STATUS>
<RPC_CLIENTID>f1e13e50-bcba-45fc-b6b1-3d56321921afRPC_CLIENTID>
<RPC_CALLID>3RPC_CALLID>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_IDOPCODE>
<DATA>
<TXID>7TXID>
<BLOCK_ID>1073741825BLOCK_ID>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2OPCODE>
<DATA>
<TXID>8TXID>
<GENSTAMPV2>1001GENSTAMPV2>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCKOPCODE>
<DATA>
<TXID>9TXID>
<PATH>/sanguo/wei/caocao._COPYING_PATH>
<BLOCK>
<BLOCK_ID>1073741825BLOCK_ID>
<NUM_BYTES>0NUM_BYTES>
<GENSTAMP>1001GENSTAMP>
BLOCK>
<RPC_CLIENTID>RPC_CLIENTID>
<RPC_CALLID>-2RPC_CALLID>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_CLOSEOPCODE>
<DATA>
<TXID>10TXID>
<LENGTH>0LENGTH>
<INODEID>0INODEID>
<PATH>/sanguo/wei/caocao._COPYING_PATH>
<REPLICATION>3REPLICATION>
<MTIME>1625023366262MTIME>
<ATIME>1625023365316ATIME>
<BLOCKSIZE>134217728BLOCKSIZE>
<CLIENT_NAME>CLIENT_NAME>
<CLIENT_MACHINE>CLIENT_MACHINE>
<OVERWRITE>falseOVERWRITE>
<BLOCK>
<BLOCK_ID>1073741825BLOCK_ID>
<NUM_BYTES>15NUM_BYTES>
<GENSTAMP>1001GENSTAMP>
BLOCK>
<PERMISSION_STATUS>
<USERNAME>bdUSERNAME>
<GROUPNAME>supergroupGROUPNAME>
<MODE>420MODE>
PERMISSION_STATUS>
DATA>
RECORD>
<RECORD>
<OPCODE>OP_RENAME_OLDOPCODE>
<DATA>
<TXID>11TXID>
<LENGTH>0LENGTH>
<SRC>/sanguo/wei/caocao._COPYING_SRC>
<DST>/sanguo/wei/caocaoDST>
<TIMESTAMP>1625023366270TIMESTAMP>
<RPC_CLIENTID>f1e13e50-bcba-45fc-b6b1-3d56321921afRPC_CLIENTID>
<RPC_CALLID>9RPC_CALLID>
DATA>
RECORD>
EDITS>
NN通过seen.txid能够确定下次合并的Edits文件内容。
默认情况下,2NN每隔1小时执行一次
<property>
<name>dfs.namenode.checkpoint.periodname>
<value>3600value>
property>
默认情况下,一分钟检查一次操作次数,当操作次数达到 1 百万时,2NN 执行一次。
<property>
<name>dfs.namenode.checkpoint.txnsname>
<value>1000000value>
<description>操作动作次数description>
property>
<property>
<name>dfs.namenode.checkpoint.check.periodname>
<value>60value>
<description> 1 分钟检查一次操作次数description>
property >
可以通过hdfs-site.xml
进行配置
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.periodname>
<value>120value>
property>
<property>
<name>dfs.namenode.name.dirname>
<value>/opt/module/hadoop-2.7.2/data/tmp/dfs/namevalue>
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
集群处于安全模式,不能执行重要操作(写操作,如上传文件会失败)。集群启动完成后,自动退出安全模式。
## 安全模式相关命令
### 查看安全模式状态
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
信息,文件也被上传成功了。
NameNode 的本地目录可以配置成多个,且每个目录存放内容相同,可以增加可靠性
具体配置如下:
1、先初始化所有的集群:关闭集群、删除logs和data
2、在hdfs-site.xml中增加以下内容,并将配置文件分发到各个服务器上
<property>
<name>dfs.namenode.name.dirname>
<value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2value>
property>
3、格式化NN(hdfs namenode -format),这里要等配置完成之后再格式化,因为格式化的时候就会读取配置文件去创建NN的目录了
4、启动集群(start-dfs.sh)
5、上传一个文件
hadoop fs -put caocao /caocao
6、查看两个namex目录下的内容,发现两个内容均相同。