HdfsAPI使用
1 Shell命令类型
1.1 基本语法
hadoop fs [具体命令] 或者 hdfs dfs [具体命令]
dfs是fs的实现类
1.2 类型
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum [-v] <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-concat <target path> <src path> <src path> ...]
[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] [-s] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-v] [-x] <path> ...]
[-expunge [-immediate] [-fs <path>]]
[-find <path> ... <expression> ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {-n name | -d} [-e en] <path>]
[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
[-head <file>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setfattr {-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] [-s <sleep interval>] <file>]
[-test -[defswrz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touch [-a] [-m] [-t TIMESTAMP (yyyyMMdd:HHmmss) ] [-c] <path> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
1.3 说明
(1)-help: 输出这个命令参数
> hadoop fs -help rm
(2)-ls: 显示目录信息
> hadoop fs -ls /
(3)-mkdir: 在 HDFS 上创建目录
> hadoop fs -mkdir /user/temp
(4)-moveFromLocal: 从本地剪切粘贴到 HDFS
> hadoop fs -moveFromLocal test1.txt /user/temp/test1.txt
(5)-appendToFile: 追加一个文件到已经存在的文件末尾
> hadoop fs -appendToFile test2.txt /user/temp/test1.txt
(6)-cat: 显示文件内容
> hadoop fs -cat /user/temp/test1.txt
(7)-chgrp 、 -chmod、 -chown: Linux 文件系统中的用法一样, 修改文件所属权限
> hadoop fs -chmod 666 /user/temp/test1.txt
(8)-copyFromLocal: 从本地文件系统中拷贝文件到 HDFS 路径去
> hadoop fs -copyFromLocal test2.txt /user/temp/test2.txt
(9)-copyToLocal: 从 HDFS 拷贝到本地
> hadoop fs -copyToLocal /user/temp/test1.txt ./
(10) -cp : 从 HDFS 的一个路径拷贝到 HDFS 的另一个路径
> hadoop fs -cp /user/temp/test1.txt /user/temp2/test1.txt
(11)-mv: 在 HDFS 目录中移动文件
> hadoop fs -mv /user/temp/test2.txt /user/temp2/text2.txt
(12)-get: 等同于 copyToLocal, 就是从 HDFS 下载文件到本地
> hadoop fs -get /user/temp2/text2.txt
(13)-getmerge: 合并下载多个文件, 比如 HDFS 的目录/user/temp2/下有多个文件:log.1,log.2,log.3,…
> hadoop fs -getmerge /user/temp2/* ./merge.txt
(14)-put: 等同于 copyFromLocal
> hadoop fs -put test3.txt /user/temp2/
(15)-tail: 显示一个文件的末尾
> hadoop fs -tail /user/temp2/test3.txt
(16)-rm: 删除文件或文件夹
删除文件夹时需要加上 -r
> hadoop fs -rm -r /user/temp2/
(17)-rmdir: 删除空目录
> hadoop fs -rmdir /user/temp
目录不为空则无法删除
(18)-du 统计文件夹的大小信息
> hadoop fs -du -s -h /demo/api/test1
(19)-setrep: 设置 HDFS 中文件的副本数量
> hadoop fs -setrep 4 /demo/api/test1/renameTile.txt
这里设置的副本数只是记录在 NameNode 的元数据中, 是否真的会有这么多副本, 还得
看 DataNode 的数量。 因为目前只有 3 台设备, 最多也就 3 个副本, 只有节点数的增加到 10
台时, 副本数才能达到 10。
2 API命令
2.1 环境准备
1.解压在开发机器上解压hadoop-3.3.1.tar.gz(略过)
2.配置环境变量(略过)
3.安装winutils.exe和hadoop.dll
GitHub上找编译好的winutils.exe和hadoop.dll(编译环境比较麻烦,我没找到3.3.1的但是找到了3.2.1的试了一下可以用)
# windows编译环境,不嫌麻烦可以试一下
----------------------------------------------------------------------------------
Building on Windows
----------------------------------------------------------------------------------
Requirements:
* Windows System
* JDK 1.8
* Maven 3.0 or later
* Protocol Buffers 3.7.1
* CMake 3.1 or newer
* Visual Studio 2010 Professional or Higher
* Windows SDK 8.1 (if building CPU rate control for the container executor)
* zlib headers (if building native code bindings for zlib)
* Internet connection for first build (to fetch all Maven and Hadoop dependencies)
* Unix command-line tools from GnuWin32: sh, mkdir, rm, cp, tar, gzip. These
tools must be present on your PATH.
* Python ( for generation of docs using 'mvn site')
Unix command-line tools are also included with the Windows Git package which
can be downloaded from http://git-scm.com/downloads
If using Visual Studio, it must be Professional level or higher.
Do not use Visual Studio Express. It does not support compiling for 64-bit,
which is problematic if running a 64-bit system.
The Windows SDK 8.1 is available to download at:
http://msdn.microsoft.com/en-us/windows/bg162891.aspx
Cygwin is not required.
----------------------------------------------------------------------------------
Building:
Keep the source code tree in a short path to avoid running into problems related
to Windows maximum path length limitation (for example, C:\hdc).
There is one support command file located in dev-support called win-paths-eg.cmd.
It should be copied somewhere convenient and modified to fit your needs.
win-paths-eg.cmd sets up the environment for use. You will need to modify this
file. It will put all of the required components in the command path,
configure the bit-ness of the build, and set several optional components.
Several tests require that the user must have the Create Symbolic Links
privilege.
All Maven goals are the same as described above with the exception that
native code is built by enabling the 'native-win' Maven profile. -Pnative-win
is enabled by default when building on Windows since the native components
are required (not optional) on Windows.
If native code bindings for zlib are required, then the zlib headers must be
deployed on the build machine. Set the ZLIB_HOME environment variable to the
directory containing the headers.
set ZLIB_HOME=C:\zlib-1.2.7
At runtime, zlib1.dll must be accessible on the PATH. Hadoop has been tested
with zlib 1.2.7, built using Visual Studio 2010 out of contrib\vstudio\vc10 in
the zlib 1.2.7 source tree.
http://www.zlib.net/
----------------------------------------------------------------------------------
Building distributions:
* Build distribution with native code : mvn package [-Pdist][-Pdocs][-Psrc][-Dtar][-Dmaven.javadoc.skip=true]
4.将winutils.exe放到解压的hadoop的bin目录下
5.将hadoop.dll放到C:\Window\System32下
2.2 代码准备
- 启动之前搭好的hadoop集群(废话)
- 搭建一个maven工程
- 引入maven依赖
<dependencies>
<!--hadoop依赖-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2.3 例子
测试类基本结构
2.3.1 获取文件系统及关闭
获取文件系统
@Before
public void getFs() throws IOException {
// 1 获取文件系统(方法1)
// 设置hadoop用户
System.setProperty("HADOOP_USER_NAME", "hadoop");
// 创建配置
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://hadoop110:9000");
// 设置副本数量(实际副本数量不可能大于DateNode节点数,即便你设置的大于节点数)
configuration.set("dfs.replication", "10");
// 获取文件系统
fs = FileSystem.get(configuration);
// 1 获取文件系统(方法2)
// FileSystem fs = FileSystem.get(new URI("hdfs://hadoop110:9000"), new Configuration(), "hadoop");
}
关闭文件系统
@After
public void closeFs() throws IOException {
// 3 关闭资源
fs.close();
}
2.3.2 创建目录
@Test
public void mkdir() throws IOException {
// 创建目录
boolean result = fs.mkdirs(new Path("/demo/api/test1"));
System.out.println(result);
}
2.3.3 删除目录或文件
@Test
public void delete() throws IOException {
// 删除目录
boolean result = fs.delete(new Path("/demo/api/test"), false);
System.out.println(result);
}
2.3.4 上传文件
方式一
@Test
public void copyFromLocalFile() throws IOException {
// 上传本地文件到hdfs
fs.copyFromLocalFile(new Path("D:/study/hadoop/我是测试文件.txt"), new Path("/demo/api/test1/我是测试文件.txt"));
}
方式二
@Test
public void create() throws IOException {
// 创建输入流
FileInputStream inputStream = new FileInputStream(new File("D:/study/hadoop/create.txt"));
// 获取输出流
FSDataOutputStream outputStream = fs.create(new Path("/demo/api/test1/create.txt"));
// 拷贝流
IOUtils.copyBytes(inputStream, outputStream, configuration);
// 关闭资源
IOUtils.closeStream(inputStream);
IOUtils.closeStream(outputStream);
}
2.3.5 下载文件
方式一
@Test
public void copyToLocalFile() throws IOException {
// 下载文件
fs.copyToLocalFile(false, new Path("/demo/api/test1/replicationTest.txt"), new Path("D:/study/hadoop/downloadTest.txt"), true);
}
方式二
@Test
public void open() throws IOException {
// 获取输入流
FSDataInputStream inputStream = fs.open(new Path("/demo/api/test1/create.txt"));
// 创建输出流
FileOutputStream outputStream = new FileOutputStream(new File("D:/study/hadoop/createDownload.txt"));
// 拷贝流
IOUtils.copyBytes(inputStream, outputStream, configuration);
// 关闭资源
IOUtils.closeStream(inputStream);
IOUtils.closeStream(outputStream);
}
2.3.6 副本数量测试
设置副本数量为10片,大于实际的3个DataNode
// 设置副本数量(实际副本数量不可能大于DateNode节点数,即便你设置的大于节点数)
configuration.set("dfs.replication", "10");
@Test
public void replicationTest() throws IOException {
// 副本数量测试(实际副本数量不可能大于DateNode节点数,即便你设置的大于节点数)
fs.copyFromLocalFile(new Path("D:/study/hadoop/replicationTest.txt"), new Path("/demo/api/test1/replicationTest.txt"));
}
网页端查看副本数
这里似乎看上去和设置的一样,但是我一共就三个节点,不可能有10个。
# 查看实际副本数
hdfs fsck /demo/api/test1/replicationTest.txt -files -blocks
# 结果
Connecting to namenode via http://hadoop110:9870/fsck?ugi=hadoop&files=1&blocks=1&path=%2Fdemo%2Fapi%2Ftest1%2FreplicationTest.txt
FSCK started by hadoop (auth:SIMPLE) from /192.168.40.110 for path /demo/api/test1/replicationTest.txt at Wed Sep 08 10:44:41 CST 2021
/demo/api/test1/replicationTest.txt 21 bytes, replicated: replication=10, 1 block(s): Under replicated BP-1927473396-192.168.40.110-1629372952977:blk_1073741851_1027. Target Replicas is 10 but found 3 live replica(s), 0 decommissioned replica(s), 0 decommissioning replica(s).
0. BP-1927473396-192.168.40.110-1629372952977:blk_1073741851_1027 len=21 Live_repl=3
Status: HEALTHY
Number of data-nodes: 3
Number of racks: 1
Total dirs: 0
Total symlinks: 0
Replicated Blocks:
Total size: 21 B
Total files: 1
Total blocks (validated): 1 (avg. block size 21 B)
Minimally replicated blocks: 1 (100.0 %)
Over-replicated blocks: 0 (0.0 %)
Under-replicated blocks: 1 (100.0 %)
Mis-replicated blocks: 0 (0.0 %)
Default replication factor: 3
Average block replication: 3.0
Missing blocks: 0
Corrupt blocks: 0
Missing replicas: 7 (70.0 %)
Blocks queued for replication: 0
Erasure Coded Block Groups:
Total size: 0 B
Total files: 0
Total block groups (validated): 0
Minimally erasure-coded block groups: 0
Over-erasure-coded block groups: 0
Under-erasure-coded block groups: 0
Unsatisfactory placement block groups: 0
Average block group size: 0.0
Missing block groups: 0
Corrupt block groups: 0
Missing internal blocks: 0
Blocks queued for replication: 0
FSCK ended at Wed Sep 08 10:44:41 CST 2021 in 3 milliseconds
The filesystem under path '/demo/api/test1/replicationTest.txt' is HEALTHY
可以看到实际副本数量是3片,有7个副本属于丢失状态。
关于副本数量大于集群DateNode数量如果加入新的节点,副本数量会增加,直到和设置的数量一样为止就不在增加。
设置副本数为2,小于实际的3个DataNode
// 设置副本数量(实际副本数量不可能大于DateNode节点数,即便你设置的大于节点数)
configuration.set("dfs.replication", "2");
@Test
public void replicationTest() throws IOException {
// 副本数量测试(实际副本数量不可能大于DateNode节点数,即便你设置的大于节点数)
fs.copyFromLocalFile(new Path("D:/study/hadoop/replicationTest2.txt"), new Path("/demo/api/test1/replicationTest2.txt"));
}
网页端查看副本数
如果不设置副本数,实际将会是hdfs配置的默认副本数。
2.3.7 重命名文件
@Test
public void rename() throws IOException {
// 更改文件名
fs.rename(new Path("/demo/api/test1/replicationTest2.txt"), new Path("/demo/api/test1/renameTile.txt"));
}
2.3.8 查看文件详情
@Test
public void listFiles() throws IOException {
// 查看文件详情
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/demo/api/test1/"), true);
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.next();
// 文件名称
System.out.println(fileStatus.getPath().getName());
// 文件长度
System.out.println(fileStatus.getLen());
// 文件权限
System.out.println(fileStatus.getPermission());
// 文件分组
System.out.println(fileStatus.getGroup());
// 文件存储的块信息
for (BlockLocation blockLocation : fileStatus.getBlockLocations()) {
String[] hosts = blockLocation.getCachedHosts();
System.out.println(JSON.toJSONString(hosts));
}
System.out.println("======================分割线======================");
}
}
2.3.9 判断文件和文件夹
@Test
public void listStatus() throws IOException {
// 查看文件详情
FileStatus[] listStatus = fs.listStatus(new Path("/demo/api/test1/renameTile.txt"));
for (FileStatus fileStatus : listStatus) {
if (fileStatus.isDirectory()) {
System.out.println(fileStatus.getPath().getName() + " is directory");
} else if (fileStatus.isFile()) {
System.out.println(fileStatus.getPath().getName() + " is file");
} else {
System.out.println(fileStatus.getPath().getName() + " is impossible");
}
}
}
2.3.10 文件定位读取
1.先上传一个文件(过程参考前面)
2.分块下载
@Test
public void readFile1() throws IOException {
// 获取输入流
FSDataInputStream inputStream = fs.open(new Path("/demo/api/test1/jdk-8u201-linux-x64.tar.gz"));
// 创建输出流
FileOutputStream outputStream = new FileOutputStream(new File("D:/study/hadoop/jdk-8u201-linux-x64.tar.gz.part1"));
// 拷贝流
byte[] buf = new byte[1024];
for (int i = 0; i < 1024 * 128; i++) {
int read = inputStream.read(buf);
if (read > 0) {
outputStream.write(buf);
}
}
// 关闭资源
IOUtils.closeStream(inputStream);
IOUtils.closeStream(outputStream);
}
@Test
public void readFile2() throws IOException {
// 获取输入流
FSDataInputStream inputStream = fs.open(new Path("/demo/api/test1/jdk-8u201-linux-x64.tar.gz"));
// 创建输出流
FileOutputStream outputStream = new FileOutputStream(new File("D:/study/hadoop/jdk-8u201-linux-x64.tar.gz.part2"));
// 定位输入数据位置
inputStream.seek(1024 * 1024 * 128);
// 拷贝流
IOUtils.copyBytes(inputStream, outputStream, configuration);
// 关闭资源
IOUtils.closeStream(inputStream);
IOUtils.closeStream(outputStream);
}
3.下载完成后拼接数据
type jdk-8u201-linux-x64.tar.gz.part2 >> jdk-8u201-linux-x64.tar.gz.part1
可以看到拼接完成后数据大小和原文件一致,修改名称后解压完成正常。
3 HDFS数据流
3.1 HDFS写数据流程
3.1.1 流程图
3.1.2 步骤说明
- 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
- NameNode 返回是否可以上传。
- 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
- NameNode 返回 3 个 DataNode 节点,分别为 dn1、 dn2、 dn3。
- 客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
- dn1、 dn2、 dn3 逐级应答客户端。
- 客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存), 以Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet 会放入一个应答队列等待应答。
- 当一个 Block 传输完成之后, 客户端再次请求 NameNode 上传第二个 Block 的服务器。
3.1.3 网络拓扑-节点距离计算
在 HDFS 写数据的过程中, NameNode 会选择距离待上传数据最近距离的 DataNode 接
收数据。
节点距离: 两个节点到达最近的共同祖先的距离总和。
3.1.4 机架感知(副本存储节点选择)
机架感知说明
http://hadoop.apache.org/docs/r3.3.1/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html#Data_Replication
3.2 HDFS读数据流程
3.2.1 流程图
3.2.2 步骤说明
- 客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode 通过查询元
数据,找到文件块所在的 DataNode 地址。 - 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
- DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校
验)。 - 客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
4 NameNode 和 SecondaryNameNode
4.1 NN 和 2NN 工作机制
如果存储在 NameNode 节点的磁盘中, 因为经常需要进行随机访问, 还有响应客户请求, 必然是效率过低。 因此, 元数据需要存放在内存中。 但如果只存在内存中, 一旦断电, 元数据丢失, 整个集群就无法工作了。 因此产生在磁盘中备份元数据的FsImage。
这样又会带来新的问题, 当在内存中的元数据更新时, 如果同时更新 FsImage, 就会导致效率过低, 但如果不更新, 就会发生一致性问题, 一旦 NameNode 节点断电, 就会产生数据丢失。 因此, 引入 Edits 文件(只进行追加操作, 效率很高)。 每当元数据有更新或者添加元数据时, 修改内存中的元数据并追加到 Edits 中。 这样, 一旦 NameNode 节点断电, 可以通过 FsImage 和 Edits 的合并, 合成元数据。
但是, 如果长时间添加数据到 Edits 中, 会导致该文件数据过大, 效率降低, 而且一旦断电, 恢复元数据需要的时间过长。 因此, 需要定期进行 FsImage 和 Edits 的合并, 如果这个操作由 NameNode节点完成,又会效率过低。因此,引入一个新的节点 SecondaryNamenode,专门用于 FsImage 和 Edits 的合并。
4.1.1 NameNode工作机制
4.1.2 步骤说明
1.第一阶段: NameNode 启动
(1)第一次启动 NameNode 格式化后,创建 Fsimage 和 Edits 文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
(2)客户端对元数据进行增删改的请求。
(3)NameNode 记录操作日志,更新滚动日志。
(4)NameNode 在内存中对元数据进行增删改。
2.第二阶段: 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。
4.1.3 NN 和 2NN 工作机制详解:
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 中。
4.2 Fsimage 和 Edits
4.2.1 概念
NameNode被格式化之后,将在/opt/module/hadoop-3.3.1/data/tmp/dfs/name/current中产生如下文件
fsimage_0000000000000000000
fsimage_0000000000000000000.md5
seen_txid
VERSION
(1)Fsimage文件:HDFS文件系统元数据的一个永久性额检查点,其中包含HDFS文件系统的所有目录和文件inode的序列化信息。
(2)Edits文件:存放HDFS文件系统所有更新操作的路径,人家系统客户端执行的所有写操作首先会被记录到Edits文件中。
(3)seen_txid文件:保存的是一个数字,就是最后一个Edits的数字。
(4)每次NameNode启动的时候都会讲Fsimage文件读入内存,加载Edits里面的更新操作,保证内存里的元数据信息是最新的、同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并。
4.2.2 oiv 查看 Fsimage 文件
1.基本语法
hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径
2.操作
# 进入目录
> pwd
/opt/module/hadoop-3.3.1/data/tmp/dfs/name/current
# 查看
> hdfs oiv -p XML -i fsimage_0000000000000000325 -o /home/hadoop/fsimage.xml
3.结果
<?xml version="1.0"?>
<fsimage><version><layoutVersion>-66</layoutVersion><onDiskVersion>1</onDiskVersion><oivRevision>a3b9c37a397ad4188041dd80621bdeefc46885f2</oivRevision></version>
<NameSection><namespaceId>1547933980</namespaceId><genstampV1>1000</genstampV1><genstampV2>1036</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073741860</lastAllocatedBlockId><txid>325</txid></NameSection>
<ErasureCodingSection>
<erasureCodingPolicy>
<policyId>1</policyId><policyName>RS-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
</erasureCodingPolicy>
<erasureCodingPolicy>
<policyId>2</policyId><policyName>RS-3-2-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>3</dataUnits><parityUnits>2</parityUnits></ecSchema>
</erasureCodingPolicy>
<erasureCodingPolicy>
<policyId>3</policyId><policyName>RS-LEGACY-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs-legacy</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
</erasureCodingPolicy>
<erasureCodingPolicy>
<policyId>4</policyId><policyName>XOR-2-1-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>xor</codecName><dataUnits>2</dataUnits><parityUnits>1</parityUnits></ecSchema>
</erasureCodingPolicy>
<erasureCodingPolicy>
<policyId>5</policyId><policyName>RS-10-4-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
<codecName>rs</codecName><dataUnits>10</dataUnits><parityUnits>4</parityUnits></ecSchema>
</erasureCodingPolicy>
</ErasureCodingSection>
<INodeSection><lastInodeId>16462</lastInodeId><numInodes>46</numInodes><inode><id>16385</id><type>DIRECTORY</type><name></name><mtime>1630826570349</mtime><permission>hadoop:supergroup:0755</permission><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16386</id><type>DIRECTORY</type><name>tmp</name><mtime>1629512731158</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16387</id><type>DIRECTORY</type><name>hadoop-yarn</name><mtime>1629375870036</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16388</id><type>DIRECTORY</type><name>staging</name><mtime>1629512725296</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16389</id><type>DIRECTORY</type><name>history</name><mtime>1629375870165</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16390</id><type>DIRECTORY</type><name>done</name><mtime>1629513418327</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16391</id><type>DIRECTORY</type><name>done_intermediate</name><mtime>1629512738173</mtime><permission>hadoop:supergroup:1777</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16392</id><type>DIRECTORY</type><name>user</name><mtime>1631158286624</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16393</id><type>DIRECTORY</type><name>hadoop</name><mtime>1629513521534</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16394</id><type>DIRECTORY</type><name>input</name><mtime>1629511391839</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16395</id><type>FILE</type><name>wc.input</name><replication>3</replication><mtime>1629511023636</mtime><atime>1629511022631</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741825</id><genstamp>1001</genstamp><numBytes>52</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16396</id><type>FILE</type><name>jdk-8u261-linux-x64.tar.gz</name><replication>3</replication><mtime>1629511391831</mtime><atime>1631153193358</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741826</id><genstamp>1002</genstamp><numBytes>134217728</numBytes></block>
<block><id>1073741827</id><genstamp>1003</genstamp><numBytes>8894075</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16397</id><type>DIRECTORY</type><name>hadoop</name><mtime>1629512725296</mtime><permission>hadoop:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16398</id><type>DIRECTORY</type><name>.staging</name><mtime>1629514083172</mtime><permission>hadoop:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16404</id><type>DIRECTORY</type><name>logs</name><mtime>1629512731309</mtime><permission>hadoop:hadoop:1777</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16405</id><type>DIRECTORY</type><name>hadoop</name><mtime>1629512731332</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16406</id><type>DIRECTORY</type><name>bucket-logs-tfile</name><mtime>1629513513250</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16407</id><type>DIRECTORY</type><name>0001</name><mtime>1629512731376</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16408</id><type>DIRECTORY</type><name>application_1629373743420_0001</name><mtime>1629513313276</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16409</id><type>DIRECTORY</type><name>hadoop</name><mtime>1629514138083</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16416</id><type>FILE</type><name>job_1629373743420_0001-1629512728156-hadoop-word+count-1629513304564-0-0-FAILED-default-1629512742245.jhist</name><replication>3</replication><mtime>1629513305534</mtime><atime>1629513305092</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0770</permission><blocks><block><id>1073741835</id><genstamp>1011</genstamp><numBytes>24579</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16417</id><type>FILE</type><name>job_1629373743420_0001_conf.xml</name><replication>3</replication><mtime>1629513305592</mtime><atime>1629513305546</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0770</permission><blocks><block><id>1073741836</id><genstamp>1012</genstamp><numBytes>270105</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16418</id><type>FILE</type><name>hadoop110_38377</name><replication>3</replication><mtime>1629513312725</mtime><atime>1629513312627</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:hadoop:0640</permission><blocks><block><id>1073741837</id><genstamp>1013</genstamp><numBytes>13870</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16419</id><type>FILE</type><name>localhost_35037</name><replication>3</replication><mtime>1629513313271</mtime><atime>1629513313143</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:hadoop:0640</permission><blocks><block><id>1073741838</id><genstamp>1014</genstamp><numBytes>119495</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16420</id><type>DIRECTORY</type><name>2021</name><mtime>1629513418327</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16421</id><type>DIRECTORY</type><name>08</name><mtime>1629513418327</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16422</id><type>DIRECTORY</type><name>21</name><mtime>1629513418327</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16423</id><type>DIRECTORY</type><name>000000</name><mtime>1629514138083</mtime><permission>hadoop:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16429</id><type>DIRECTORY</type><name>0002</name><mtime>1629513513254</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16430</id><type>DIRECTORY</type><name>application_1629373743420_0002</name><mtime>1629514089649</mtime><permission>hadoop:hadoop:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16432</id><type>DIRECTORY</type><name>output</name><mtime>1629514081833</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16438</id><type>FILE</type><name>part-r-00000</name><replication>3</replication><mtime>1629514081627</mtime><atime>1629514081406</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741845</id><genstamp>1021</genstamp><numBytes>63</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16440</id><type>FILE</type><name>_SUCCESS</name><replication>3</replication><mtime>1629514081835</mtime><atime>1629514081833</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><storagePolicyId>0</storagePolicyId></inode>
<inode><id>16443</id><type>FILE</type><name>job_1629373743420_0002-1629513512969-hadoop-word+count-1629514081841-1-1-SUCCEEDED-default-1629513521448.jhist</name><replication>3</replication><mtime>1629514082001</mtime><atime>1629514081970</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0770</permission><blocks><block><id>1073741847</id><genstamp>1023</genstamp><numBytes>33354</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16444</id><type>FILE</type><name>job_1629373743420_0002_conf.xml</name><replication>3</replication><mtime>1629514082084</mtime><atime>1629514082017</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0770</permission><blocks><block><id>1073741848</id><genstamp>1024</genstamp><numBytes>270105</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16445</id><type>FILE</type><name>hadoop110_38377</name><replication>3</replication><mtime>1629514089647</mtime><atime>1629514089585</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:hadoop:0640</permission><blocks><block><id>1073741849</id><genstamp>1025</genstamp><numBytes>237884</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16446</id><type>DIRECTORY</type><name>demo</name><mtime>1630826570349</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16447</id><type>DIRECTORY</type><name>api</name><mtime>1630827263324</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16449</id><type>DIRECTORY</type><name>test1</name><mtime>1631091340113</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16450</id><type>FILE</type><name>我是测试文件.txt</name><replication>3</replication><mtime>1631068318480</mtime><atime>1631150546741</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741850</id><genstamp>1026</genstamp><numBytes>27</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16451</id><type>FILE</type><name>replicationTest.txt</name><replication>10</replication><mtime>1631068704420</mtime><atime>1631092338426</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741851</id><genstamp>1027</genstamp><numBytes>21</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16453</id><type>FILE</type><name>renameTile.txt</name><replication>4</replication><mtime>1631080336810</mtime><atime>1631152714663</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741853</id><genstamp>1029</genstamp><numBytes>21</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16454</id><type>FILE</type><name>create.txt</name><replication>3</replication><mtime>1631088817160</mtime><atime>1631088816947</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741854</id><genstamp>1030</genstamp><numBytes>6</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16455</id><type>FILE</type><name>jdk-8u201-linux-x64.tar.gz</name><replication>1</replication><mtime>1631091344095</mtime><atime>1631150544760</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0644</permission><blocks><block><id>1073741855</id><genstamp>1031</genstamp><numBytes>134217728</numBytes></block>
<block><id>1073741856</id><genstamp>1032</genstamp><numBytes>57599412</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
<inode><id>16457</id><type>DIRECTORY</type><name>temp</name><mtime>1631156903833</mtime><permission>hadoop:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
<inode><id>16458</id><type>FILE</type><name>test1.txt</name><replication>3</replication><mtime>1631155750838</mtime><atime>1631154801837</atime><preferredBlockSize>134217728</preferredBlockSize><permission>hadoop:supergroup:0666</permission><blocks><block><id>1073741857</id><genstamp>1033</genstamp><numBytes>6</numBytes></block>
</blocks>
<storagePolicyId>0</storagePolicyId></inode>
</INodeSection>
<INodeReferenceSection></INodeReferenceSection><SnapshotSection><snapshotCounter>0</snapshotCounter><numSnapshots>0</numSnapshots></SnapshotSection>
<INodeDirectorySection><directory><parent>16385</parent><child>16446</child><child>16386</child><child>16392</child></directory>
<directory><parent>16386</parent><child>16387</child><child>16404</child></directory>
<directory><parent>16387</parent><child>16388</child></directory>
<directory><parent>16388</parent><child>16397</child><child>16389</child></directory>
<directory><parent>16389</parent><child>16390</child><child>16391</child></directory>
<directory><parent>16390</parent><child>16420</child></directory>
<directory><parent>16391</parent><child>16409</child></directory>
<directory><parent>16392</parent><child>16393</child><child>16457</child></directory>
<directory><parent>16393</parent><child>16394</child><child>16432</child></directory>
<directory><parent>16394</parent><child>16396</child><child>16395</child></directory>
<directory><parent>16397</parent><child>16398</child></directory>
<directory><parent>16404</parent><child>16405</child></directory>
<directory><parent>16405</parent><child>16406</child></directory>
<directory><parent>16406</parent><child>16407</child><child>16429</child></directory>
<directory><parent>16407</parent><child>16408</child></directory>
<directory><parent>16408</parent><child>16418</child><child>16419</child></directory>
<directory><parent>16420</parent><child>16421</child></directory>
<directory><parent>16421</parent><child>16422</child></directory>
<directory><parent>16422</parent><child>16423</child></directory>
<directory><parent>16423</parent><child>16416</child><child>16417</child><child>16443</child><child>16444</child></directory>
<directory><parent>16429</parent><child>16430</child></directory>
<directory><parent>16430</parent><child>16445</child></directory>
<directory><parent>16432</parent><child>16440</child><child>16438</child></directory>
<directory><parent>16446</parent><child>16447</child></directory>
<directory><parent>16447</parent><child>16449</child></directory>
<directory><parent>16449</parent><child>16450</child><child>16454</child><child>16455</child><child>16453</child><child>16451</child></directory>
<directory><parent>16457</parent><child>16458</child></directory>
</INodeDirectorySection>
<FileUnderConstructionSection></FileUnderConstructionSection>
<SecretManagerSection><currentId>0</currentId><tokenSequenceNumber>0</tokenSequenceNumber><numDelegationKeys>0</numDelegationKeys><numTokens>0</numTokens></SecretManagerSection><CacheManagerSection><nextDirectiveId>1</nextDirectiveId><numDirectives>0</numDirectives><numPools>0</numPools></CacheManagerSection>
</fsimage>
4.2.3 oev 查看 Edits 文件
1.基本语法
hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径
2.操作
# 进入目录
> pwd
/opt/module/hadoop-3.3.1/data/tmp/dfs/name/current
# 查看
> hdfs oev -p XML -i edits_0000000000000000315-0000000000000000323 -o /home/hadoop/edits.xml
3.结果
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EDITS>
<EDITS_VERSION>-66</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>315</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>316</TXID>
<LENGTH>0</LENGTH>
<INODEID>16462</INODEID>
<PATH>/user/temp2/test3.txt._COPYING_</PATH>
<REPLICATION>3</REPLICATION>
<MTIME>1631157801349</MTIME>
<ATIME>1631157801349</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-920481959_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.40.110</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>hadoop</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<ERASURE_CODING_POLICY_ID>0</ERASURE_CODING_POLICY_ID>
<RPC_CLIENTID>f7492ba0-7180-41a3-9da3-23027615a547</RPC_CLIENTID>
<RPC_CALLID>3</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
<DATA>
<TXID>317</TXID>
<BLOCK_ID>1073741860</BLOCK_ID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
<DATA>
<TXID>318</TXID>
<GENSTAMPV2>1036</GENSTAMPV2>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCK</OPCODE>
<DATA>
<TXID>319</TXID>
<PATH>/user/temp2/test3.txt._COPYING_</PATH>
<BLOCK>
<BLOCK_ID>1073741860</BLOCK_ID>
<NUM_BYTES>0</NUM_BYTES>
<GENSTAMP>1036</GENSTAMP>
</BLOCK>
<RPC_CLIENTID/>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_CLOSE</OPCODE>
<DATA>
<TXID>320</TXID>
<LENGTH>0</LENGTH>
<INODEID>0</INODEID>
<PATH>/user/temp2/test3.txt._COPYING_</PATH>
<REPLICATION>3</REPLICATION>
<MTIME>1631157801520</MTIME>
<ATIME>1631157801349</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME/>
<CLIENT_MACHINE/>
<OVERWRITE>false</OVERWRITE>
<BLOCK>
<BLOCK_ID>1073741860</BLOCK_ID>
<NUM_BYTES>6</NUM_BYTES>
<GENSTAMP>1036</GENSTAMP>
</BLOCK>
<PERMISSION_STATUS>
<USERNAME>hadoop</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_RENAME_OLD</OPCODE>
<DATA>
<TXID>321</TXID>
<LENGTH>0</LENGTH>
<SRC>/user/temp2/test3.txt._COPYING_</SRC>
<DST>/user/temp2/test3.txt</DST>
<TIMESTAMP>1631157801526</TIMESTAMP>
<RPC_CLIENTID>f7492ba0-7180-41a3-9da3-23027615a547</RPC_CLIENTID>
<RPC_CALLID>8</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_DELETE</OPCODE>
<DATA>
<TXID>322</TXID>
<LENGTH>0</LENGTH>
<PATH>/user/temp2</PATH>
<TIMESTAMP>1631158286624</TIMESTAMP>
<RPC_CLIENTID>8e250740-959c-4bd0-bc41-6ea35f1a8a50</RPC_CLIENTID>
<RPC_CALLID>3</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_END_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>323</TXID>
</DATA>
</RECORD>
</EDITS>
4.3 CheckPoint 时间设置
1.文件hdfs-site.xml
2.通常情况下,SecondaryNameNode 每隔一小时执行一次。
<property>
<name>dfs.namenode.checkpoint.period</name>
<value>3600</value>
</property>
3.一分钟检查一次操作次数,当操作次数达到 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 >
4.4 NameNode 故障处理
4.4.1 方法一
将 SecondaryNameNode 中数据拷贝到 NameNode 存储数据的目录;
1. kill -9 NameNode 进程
2. 删除 NameNode 存储的数据(/opt/module/hadoop-3.3.1/data/tmp/dfs/name)
3. 拷贝 SecondaryNameNode 中数据(/opt/module/hadoop-3.3.1/data/tmp/dfs/namesecondary)到原 NameNode 存储数据目录
# 进入目录
> cd /opt/module/hadoop-3.3.1/data/tmp/dfs
# 拷贝
> scp -r hadoop@hadoop130:/opt/module/hadoop-3.3.1/data/tmp/dfs/namesecondary/* ./name/
5. 重新启动 NameNode
4.4.2 方法二
使用 -importCheckpoint 选项启动 NameNode 守护进程 ,从而将 SecondaryNameNode 中数据拷贝到 NameNode 目录中。
1. 修改 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-3.3.1/data/tmp/dfs/name</value>
</property>
2. kill -9 NameNode 进程
3. 删除 NameNode 存储的数据(/opt/module/hadoop-3.3.1/data/tmp/dfs/name)
4. 如果 SecondaryNameNode 不和 NameNode 在一个主机节点上,需要将 SecondaryNameNode 存储数据的目录拷贝到 NameNode 存储数据的平级目录,并删除 in_use.lock 文件
# 进入目录
> cd /opt/module/hadoop-3.3.1/data/tmp/dfs
# 拷贝
> scp -r hadoop@hadoop130:/opt/module/hadoop-3.3.1/data/tmp/dfs/namesecondary ./
5. 导入检查点数据(等待一会 ctrl+c 结束掉)
> hdfs namenode -importCheckpoint
6. 启动 NameNode
4.5 集群安全模式
4.5.1 概述
1. NameNode启动
NameNode启动时,首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的Fsimage文件和一个空白的编辑日志。此时,NameNode开始监听DataNode请求。这个过程期间,NameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的。
2. DataNode启动
系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中。在系统正常操作期间,NameNode会在内存中保留所有块位置的映射信息。在安全模式下,各个DataNode会向NameNode发送最新的块列表信息,NameNode了解到足够多的块位置信息之后,即可高效运行文件系统。
3. 安全模式退出判断
如果满足“最小副本条件”,namenode会在30秒钟之后就退出安全模式。所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式。
4.5.2 基本语法
集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。
# 查看安全模式状态
> hdfs dfsadmin -safemode get
# 进入安全模式状态
> hdfs dfsadmin -safemode enter
# 离开安全模式状态
> hdfs dfsadmin -safemode leave
# 等待安全模式状态
> hdfs dfsadmin -safemode wait
5 DataNode
5.1 DataNode 工作机制
(1)一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode 启动后向 NameNode 注册,通过后,周期性(1小时)的向 NameNode 上报所有的块信息。
(3)心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用。
(4)集群运行中可以安全加入和退出一些机器。
5.2 数据完整性
如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),
但是存储该数据的磁盘坏了, 一直显示是绿灯, 是否很危险? 同理 DataNode 节点上的数据
损坏了, 却没有发现, 是否也很危险
(1)当 DataNode 读取 Block 的时候,它会计算 CheckSum。
(2)如果计算后的 CheckSum,与 Block 创建时值不一样,说明 Block 已经损坏。
(3)Client 读取其他 DataNode 上的 Block。
(4)DataNode 在其文件创建后周期验证 CheckSum。
5.3 掉线时限参数设置
(1)DataNode进程死亡或者网络故障造成DataNode无法与NameNode通信
(2)NameNode不会立即把该节点判定为死亡要经过一段时间,这段时间被称为超时时长。
(3)HDFS默认的超时时长为10分钟+30秒。
(4)如果定义超时时长为TimeOut则超时时长计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
需要注意的是 hdfs-site.xml 配置文件中的 heartbeat.recheck.interval 的单位为毫秒,
dfs.heartbeat.interval 的单位为秒。
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
</property>
<property>
<name>dfs.heartbeat.interval</name>
<value>3</value>
</property>
5.4 服役新数据节点
随着业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据
的需求,需要在原有集群基础上动态添加新的数据节点。
5.4.1 环境准备
(1)在 hadoop140 主机上再克隆一台 hadoop130 主机
(2)修改 IP 地址和主机名称
(3)删除原来 HDFS 文件系统留存的文件(/opt/module/hadoop-3.3.1/data 和 log)
(4)source 一下配置文件
5.4.2 服役新节点具体步骤
(1)直接启动 DataNode,即可关联到集群
hadoop-daemon.sh start datanode
yarn-daemon.sh start nodemanager
可以看到这个文件有三个副本,但是我们打开这个文件的详情看到在4个节点上都有,但是由于hadoop140是退役的,所以为了保证三个副本可用又复制了一份,也就是说退役节点的副本不算数。
5.5 退役旧数据节点
5.5.1 添加白名单
添加到白名单的主机节点, 都允许访问 NameNode, 不在白名单的主机节点, 都会被退出。
(1)在 NameNode 的/opt/module/hadoop-3.3.1/etc/hadoop 目录下创建 dfs.hosts 文件
添加如下主机名
hadoop110
hadoop120
hadoop130
hadoop140
(2)在 NameNode 的 hdfs-site.xml 配置文件中增加 dfs.hosts 属性
<property>
<name>dfs.hosts</name>
<value>/opt/module/hadoop-3.3.1/etc/hadoop/dfs.hosts</value>
</property>
(3)分发文件到其它节点
xsync hdfs-site.xml
(4)刷新 NameNode
hdfs dfsadmin -refreshNodes
(5)更新 ResourceManager 节点
yarn rmadmin -refreshNodes
(6)web 浏览器上查看
5.5.2 黑名单退役
在黑名单上面的主机都会被强制退出。
(1)在 NameNode (hadoop110)的 /opt/module/hadoop-3.3.1/etc/hadoop 目录下创建 dfs.hosts.exclude 文件
touch dfs.hosts.exclude
添加如下主机名称(要退役的节点)
hadoop140
(2)在 NameNode 的 hdfs-site.xml 配置文件中增加 dfs.hosts.exclude 属性
<property>
<name>dfs.hosts.exclude</name>
<value>/opt/module/hadoop-3.3.1/etc/hadoop/dfs.hosts.exclude</value>
</property>
(3)刷新 NameNode、刷新 ResourceManager
hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes
(4)检查 Web 浏览器,退役节点的状态为 decommission in progress(退役中),说明数据节点正在复制块到其他节点。
(5)等待退役节点状态为 decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。 注意:如果副本数是 3,服役的节点小于等于 3,是不能退役成功的,需要修改副本数后才能退役。
hadoop-daemon.sh stop datanode
yarn-daemon.sh stop nodemanager
吐槽:如果发现退役不了节点可以重启一下NameNode试一下,我卡在这2个小时…
5.6 Datanode 多目录配置
(1)DataNode 也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本
(2)具体配置 hdfs-site.xml
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>
</property>