目录
第五部分 HDFS分布式⽂件系统
第 1 节 HDFS 简介
HDFS (全称:Hadoop Distribute File System,Hadoop 分布式⽂件系统)是 Hadoop 核⼼组成,是分布式存储服务。
分布式⽂件系统横跨多台计算机,在⼤数据时代有着⼴泛的应⽤前景,它们为存储和处理超⼤规模数据提供所需的扩展能⼒。
HDFS是分布式⽂件系统中的⼀种。
第 2 节 HDFS的重要概念
HDFS 通过统⼀的命名空间⽬录树来定位⽂件; 另外,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各⾃的⻆⾊(分布式本质是拆分,各司其职);
典型的 Master/Slave 架构
HDFS 的架构是典型的 Master/Slave 结构。
HDFS集群往往是⼀个NameNode(HA架构会有两个NameNode,联邦机制)+多个DataNode组成;
NameNode是集群的主节点,DataNode是集群的从节点。
分块存储(block机制)
HDFS 中的⽂件在物理上是分块存储(block)的,块的⼤⼩可以通过配置参数来规定;
Hadoop2.x版本中默认的block⼤⼩是128M;
命名空间(NameSpace)
HDFS ⽀持传统的层次型⽂件组织结构。⽤户或者应⽤程序可以创建⽬录,然后将⽂件保存在这些⽬录⾥。⽂件系统名字空间的层次结构和⼤多数现有的⽂件系统类似:⽤户可以创建、删除、移动或重命名文件
Namenode 负责维护⽂件系统的名字空间,任何对⽂件系统名字空间或属性的修改都将被Namenode 记录下来。
HDFS提供给客户单⼀个抽象⽬录树,访问形式:hdfs://namenode的hostname:port/test/input
hdfs://linux121:9000/test/input
NameNode元数据管理
我们把⽬录结构及⽂件分块位置信息叫做元数据。
NameNode的元数据记录每⼀个⽂件所对应的block信息(block的id,以及所在的DataNode节点的信息)
DataNode数据存储
⽂件的各个 block 的具体存储管理由 DataNode 节点承担。⼀个block会有多个DataNode来存储,DataNode会定时向NameNode来汇报⾃⼰持有的block信息。
副本机制
为了容错,⽂件的所有 block 都会有副本。每个⽂件的 block ⼤⼩和副本系数都是可配置的。应⽤程序可以指定某个⽂件的副本数⽬。副本系数可以在⽂件创建的时候指定,也可以在之后改变。
副本数量默认是3个。
⼀次写⼊,多次读出
HDFS 是设计成适应⼀次写⼊,多次读出的场景,且不⽀持⽂件的随机修改。 (⽀持追加写⼊,不只⽀持随机更新)
正因为如此,HDFS 适合⽤来做⼤数据分析的底层存储服务,并不适合⽤来做⽹盘等应⽤(修改不⽅便延迟⼤⽹络开销⼤成本太⾼)
第 3 节 HDFS 架构
NameNode(nn):
Hdfs集群的管理者,Master
维护管理Hdfs的名称空间(NameSpace)
维护副本策略
记录⽂件块(Block)的映射信息
负责处理客户端读写请求
DataNode(dn):
NameNode下达命令,DataNode执⾏实际操作,Slave节点。
保存实际的数据块
负责数据块的读写
Client:
客户端上传⽂件到HDFS的时候,Client负责将⽂件切分成Block,然后进⾏上传
请求NameNode交互,获取⽂件的位置信息
读取或写⼊⽂件,与DataNode交互
Client可以使⽤⼀些命令来管理HDFS或者访问HDFS
第 4 节 HDFS 客户端操作
4.1 Shell 命令⾏操作HDFS
1. 基本语法
bin/hadoop fs 具体命令 OR bin/hdfs dfs 具体命令
2. 命令⼤全
[root@linux121 hadoop-2.9.2]# bin/hdfs dfs
Usage: hadoop fs [generic options]
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-x] <path> ...]
[-expunge]
[-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>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] <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] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
Generic options supported are:
-conf <configuration file> specify an application configuration file
-D <property=value> define a value for a given property
-fs <file:///|hdfs://namenode:port> specify default filesystem URL to use,overrides 'fs.defaultFS'property from configurations.
-jt <local|resourcemanager:port> specify a ResourceManager
-files <file1,...> specify a comma-separated list of files to be copied to the map reduce cluster
-libjars <jar1,...> specify a comma-separated list of jar files to be included in the classpath
-archives <archive1,...> specify a comma-separated list of archives to be unarchived on the compute machin
3.HDFS命令演示
1. 启动Hadoop集群(⽅便后续的测试)
[root@linux121 hadoop-2.9.2]$ sbin/start-dfs.sh
[root@linux122 hadoop-2.9.2]$ sbin/start-yarn.sh
2. -help:输出这个命令参数
[root@linux121 hadoop-2.9.2]$ hadoop fs -help rm
3. -ls: 显示⽬录信息
[root@linux121 hadoop-2.9.2]$ hadoop fs -ls /
4. -mkdir:在HDFS上创建⽬录
[root@linux121 hadoop-2.9.2]$ hadoop fs -mkdir -p /lagou/bigdata
5. -moveFromLocal:从本地剪切粘贴到HDFS
[root@linux121 hadoop-2.9.2]$ touch hadoop.txt
[root@linux121 hadoop-2.9.2]$ hadoop fs -moveFromLocal ./hadoop.txt /lagou/bigdata
6. -appendToFile:追加⼀个⽂件到已经存在的⽂件末尾
[root@linux121 hadoop-2.9.2]$ touch hdfs.txt
[root@linux121 hadoop-2.9.2]$ vi hdfs.txt
输⼊
namenode datanode block replication
[root@linux121 hadoop-2.9.2]$ hadoop fs -appendToFile hdfs.txt /lagou/bigdata/hadoop.txt
7. -cat:显示⽂件内容
[root@linux121 hadoop-2.9.2]$ hadoop fs -cat /lagou/bigdata/hadoop.t
8. -chgrp 、-chmod、-chown:Linux⽂件系统中的⽤法⼀样,修改⽂件所属权限
[root@linux121 hadoop-2.9.2]$ hadoop fs -chmod 666 /lagou/bigdata/hadoop.txt
[root@linux121 hadoop-2.9.2]$ hadoop fs -chown root:root /lagou/bigdata/hadoop.txt
9. -copyFromLocal:从本地⽂件系统中拷⻉⽂件到HDFS路径去
[root@linux121 hadoop-2.9.2]$ hadoop fs -copyFromLocal README.txt /
10. -copyToLocal:从HDFS拷⻉到本地
[root@linux121 hadoop-2.9.2]$ hadoop fs -copyToLocal /lagou/bigdata/hadoop.txt ./
11. -cp :从HDFS的⼀个路径拷⻉到HDFS的另⼀个路径
[root@linux121 hadoop-2.9.2]$ hadoop fs -cp /lagou/bigdata/hadoop.txt /hdfs.txt
12. -mv:在HDFS⽬录中移动⽂件
[root@linux121 hadoop-2.9.2]$ hadoop fs -mv /hdfs.txt /lagou/bigdata/
13. -get:等同于copyToLocal,就是从HDFS下载⽂件到本地
[root@linux121 hadoop-2.9.2]$ hadoop fs -get /lagou/bigdata/hadoop.txt ./
14. -put:等同于copyFromLocal
[root@linux121 hadoop-2.9.2]$ hadoop fs -mkdir -p /user/root/test/
#本地⽂件系统创建yarn.txt
[root@linux121 hadoop-2.9.2]$ vim yarn.txt
resourcemanager nodemanager[root@linux121 hadoop-2.9.2]$ hadoop fs -put ./yarn.txt /user/root/test/
16. -tail:显示⼀个⽂件的末尾
[root@linux121 hadoop-2.9.2]$ hadoop fs -tail /user/root/test/yarn.txt
17. -rm:删除⽂件或⽂件夹
[root@linux121 hadoop-2.9.2]$ hadoop fs -rm /user/root/test/yarn.t
18. -rmdir:删除空⽬录
[root@linux121 hadoop-2.9.2]$ hadoop fs -mkdir /test
[root@linux121 hadoop-2.9.2]$ hadoop fs -rmdir /test
19. -du统计⽂件夹的⼤⼩信息 (-s表示文件夹 -h表示文件)
[root@linux121 hadoop-2.9.2]$ hadoop fs -du -s -h /user/root/test
[root@linux121 hadoop-2.9.2]$ hadoop fs -du -h /user/root/test
20. -setrep:设置HDFS中⽂件的副本数量
[root@linux121 hadoop-2.9.2]$ hadoop fs -setrep 10 /lagou/bigdata/hadoop.txt
副本数量
这⾥设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量。因为⽬前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10
4.2 JAVA客户端
4.2.1 客户端环境准备
1. 将Hadoop-2.9.2安装包解压到⾮中⽂路径(例如:E:\hadoop-2.9.2)。
2. 配置HADOOP_HOME环境变量
3. 配置Path环境变量。
4. 创建⼀个Maven⼯程ClientDemo
5. 导⼊相应的依赖坐标+⽇志配置⽂件
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoopclient -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
为了便于控制程序运⾏打印的⽇志数量,需要在项⽬的src/main/resources⽬录下,新建⼀个⽂件,命
名为“log4j.properties”,⽂件内容:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
6. 创建包名:com.lagou.hdfs
7. 创建HdfsClient类
package com.lagou.htfs;
/**
* @author CH
* @date 2020/12/24 14:07
*/
public class HtfsClient {
@Test
public void testMkdirs() throws URISyntaxException, IOException, InterruptedException {
//1. 获取Hadoop集群的configuration对象
Configuration configuration = new Configuration();
configuration.set("fs.defaultFS", "hdfs://linux121:9000");
//2. 根据configuration获取Filesystem对象
// 注掉下面, 采用上面的方式
// FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
// 建议采用上面的方式, 可以避免用户名问题
FileSystem fs = FileSystem.get(configuration);
//3. 使用FIlesystem对象创建一个测试目录
fs.mkdirs(new Path("/api_test1"));
//4. 释放FileSystem对象(类似数据库连接)
fs.close();
}
}
遇到问题:
如果不指定操作HDFS集群的⽤户信息,默认是获取当前操作系统的⽤户信息,出现权限被拒绝的问题,报错如下:
4.2.2 HDFS的API操作
1 上传⽂件
1. 编写源代码
package com.lagou.htfs;
/**
* @author CH
* @date 2020/12/24 14:07
*/
public class HtfsClient {
FileSystem fs = null;
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
//1. 获取Hadoop集群的configuration对象
Configuration configuration = new Configuration();
//configuration.set("dfs.replication", "2");
//2. 根据configuration获取Filesystem对象
fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
}
@After
public void destroy() throws IOException {
//4. 释放FileSystem对象(类似数据库连接)
fs.close();
}
// 上传文件
@Test
public void copyFromLocalToHdfs() throws URISyntaxException, IOException, InterruptedException {
// src: 源文件目录(本地路径)
// dst: 目标目录(hdfs路径)
fs.copyFromLocalFile(new Path("D:/b.txt"), new Path("/b.txt"));
// 上传文件到hdfs默认3个副本
// 改变副本数量,
// 1, configuration对象中指定新的副本数量, 见init方法中的 dfs.replication
// 2, 配置文件hdfs-site中设置
}
}
2. 将hdfs-site.xml拷⻉到项⽬的根⽬录下
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
3. 参数优先级
参数优先级排序:(1)代码中设置的值 >(2)⽤户⾃定义配置⽂件 >(3)服务器的默认配置
2 下载⽂件
// 下载文件
@Test
public void copyFromHdfsToLocal() throws URISyntaxException, IOException, InterruptedException {
// src: 源文件目录(hdfs路径)
// dst: 目标目录(本地路径)
fs.copyToLocalFile(true, new Path("/b.txt"), new Path("D:/b.txt"));
}
3 删除⽂件/⽂件夹
// 删除文件或者文件夹
@Test
public void edelete() throws URISyntaxException, IOException, InterruptedException {
// path: 目标目录(hdfs路径)
// boolean: 是否递归删除
fs.delete(new Path("/api_test/"), true);
}
4 查看⽂件名称、权限、⻓度、块信息
// 遍历指定目录获取信息, 名称, 长度, 权限等
@Test
public void list() throws URISyntaxException, IOException, InterruptedException {
// path: 目标目录(hdfs路径)
// boolean: 是否递归
// 得到一个迭代器, 装有指定目录下所有文件信息
RemoteIterator<LocatedFileStatus> remoteIterator = fs.listFiles(new Path("/"), true);
//遍历迭代器
while(remoteIterator.hasNext()){
LocatedFileStatus fileStatus = remoteIterator.next();
// 文件名
String fileName = fileStatus.getPath().getName();
// 长度
long len = fileStatus.getLen();
// 权限
FsPermission permission = fileStatus.getPermission();
// 分组
String group = fileStatus.getGroup();
// 所属用户
String owner = fileStatus.getOwner();
// \t 是制表符
System.out.println(fileName + "\t" + len + "\t" + permission + "\t" + group + "\t" + owner);
// 块信息
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
for (BlockLocation blockLocation : blockLocations) {
String[] hosts = blockLocation.getHosts();
for (String host : hosts) {
System.out.println("主机名称" + host);
}
}
System.out.println("-----------------------------------");
}
}
5 ⽂件夹判断
// 文件以及文件夹判断
@Test
public void isFile() throws URISyntaxException, IOException, InterruptedException {
FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : fileStatuses) {
boolean flag = fileStatus.isFile();
if (flag) {
System.out.println("文件: " + fileStatus.getPath().getName());
} else {
System.out.println("文件夹: " + fileStatus.getPath().getName());
}
}
}
6 I/O流操作HDFS
以上我们使⽤的API操作都是HDFS系统框架封装好的。我们⾃⼰也可以采⽤IO流的⽅式实现⽂件的上传和下载。
6.1 ⽂件上传
1. 需求:把本地e盘上的lagou.txt⽂件上传到HDFS根⽬录
2. 编写代码
// 使用IO流操作HDFS
// 上传文件: 准备输入流读取本地文件, 使用hdfs的输出流写数据到hdfs
@Test
public void uploadFileIO() throws IOException {
//1. 读取本地文件的输入流
FileInputStream inputStream = new FileInputStream(new File("D:/lagou.txt"));
//2. 准备写数据到hdfs
FSDataOutputStream outputStream = fs.create(new Path("/lagou.txt"));
//3. 输入流数据拷贝到输出流
// 下面的方法设置缓冲区大小, 以及自动关闭流
//IOUtils.copyBytes(inputStream,outputStream,4096, true);
// 不自动关闭, 用下面的, 因为底层有默认值
IOUtils.copyBytes(inputStream,outputStream,configuration);
// 可以再次关闭流
IOUtils.closeStream(outputStream);
IOUtils.closeStream(inputStream);
}
6.2 ⽂件下载
1. 需求:从HDFS上下载lagou.txt⽂件到本地e盘上
2. 编写代码
// 使用IO流操作HDFS
// 下载文件
@Test
public void downloadFileIO() throws IOException {
//1. 读取hdfs文件的输入流
FSDataInputStream in = fs.open(new Path("/lagou.txt"));
//2. 本地文件的输出流
FileOutputStream out = new FileOutputStream(new File("D:/lagou_io_copy.txt"));
//3. 流的拷贝
IOUtils.copyBytes(in,out,configuration);
//4. 可以再次关闭流
IOUtils.closeStream(out);
IOUtils.closeStream(in);
}
6.3 seek 定位读取
1. 需求:将HDFS上的lagou.txt的内容在控制台输出两次
2. 编写代码
// seek 定位读取 hdfs 指定文件 : 使用IO流读取/lagou.txt文件,并把内容输出两次, 本质就是读取文件内容并两次输出
@Test
public void seekReadFile() throws IOException {
//1. 创建一个读取hdfs文件的输入流
FSDataInputStream in = fs.open(new Path("/lagou.txt"));
//2. 控制台输出 system.out
//3. 实现流拷贝, 输入流 → 控制台
// 下面的读取方式, 会自动结束并关闭流
// IOUtils.copyBytes(in, System.out, configuration);
//4. 采用下面的方式, 可以再次读取文件
IOUtils.copyBytes(in, System.out, 4096, false);
in.seek(0); // 定位从0偏移量(文件头部) 再次读取
IOUtils.copyBytes(in,System.out, 4096, false);
//5. 关闭输入流
IOUtils.closeStream(in);
}
注意
windows解压安装Hadoop后,在调⽤相关API操作HDFS集群时可能会报错,这是由于Hadoop安装缺少windows操作系统相关⽂件所致,如下图:
解决⽅案:
从资料⽂件夹中找到winutils.exe拷⻉放到windows系统Hadoop安装⽬录的bin⽬录下即可!!
HDFS⽂件系统权限问题
hdfs的⽂件权限机制与linux系统的⽂件权限机制类似!!
r:read w:write x:execute 权限x对于⽂件表示忽略,对于⽂件夹表示是否有权限访问其内容
如果linux系统⽤户zhangsan使⽤hadoop命令创建⼀个⽂件,那么这个⽂件在HDFS当中的owner就是zhangsan
HDFS⽂件权限的⽬的,防⽌好⼈做错事,⽽不是阻⽌坏⼈做坏事。HDFS相信你告诉我你是谁,你就是谁!!
解决⽅案
指定⽤户信息获取FileSystem对象
关闭HDFS集群权限校验
vim hdfs-site.xml
#添加如下属性 <property> <name>dfs.permissions.enabled</name> <value>false</value> </property>
修改完成之后要分发到其它节点,同时要重启HDFS集群
基于HDFS权限本身⽐较鸡肋的特点,我们可以彻底放弃HDFS的权限校验,如果⽣产环境中, 我们可以考虑借助kerberos以及sentry等安全框架来管理⼤数据集群安全。
所以我们直接修改HDFS的根⽬录权限为777
hadoop fs -chmod -R 777 /
第 5 节 HDFS读写解析
5.1 HDFS读数据流程
1. 客户端通过Distributed FileSystem向NameNode请求下载⽂件,NameNode通过查询元数据,找到⽂件块所在的DataNode地址。
2. 挑选⼀台DataNode(就近原则,然后随机)服务器,请求读取数据。
3. DataNode开始传输数据给客户端(从磁盘⾥⾯读取数据输⼊流,以Packet为单位来做校验)。
4. 客户端以Packet为单位接收,先在本地缓存,然后写⼊⽬标⽂件。
5.2 HDFS写数据流程
1. 客户端通过Distributed FileSystem模块向NameNode请求上传⽂件,NameNode检查⽬标⽂件是否已存在,⽗⽬录是否存在。
2. NameNode返回是否可以上传。
3. 客户端请求第⼀个 Block上传到哪⼏个DataNode服务器上。
4. NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
5. 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调⽤dn2,然后dn2调⽤dn3,将这个通信管道建⽴完成。
6. dn1、dn2、dn3逐级应答客户端。
7. 客户端开始往dn1上传第⼀个Block(先从磁盘读取数据放到⼀个本地内存缓存),以Packet为单位,dn1收到⼀个Packet就会传给dn2,dn2传给dn3;dn1每传⼀个packet会放⼊⼀个确认队列等待确认。
8. 当⼀个Block传输完成之后,客户端再次请求NameNode上传第⼆个Block的服务器。(重复执⾏3-7步)。
验证Packet代码
// 验证Packet
@Test
public void testUploadPacket() throws IOException {
//1 准备读取本地文件的输入流
FileInputStream in = new FileInputStream(new File("d:/lagou.txt"));
//2 准备好写出数据到hdfs的输出流
FSDataOutputStream out = fs.create(new Path("/lagou.txt"), new Progressable() {
//这个progress方法就是每传输64KB(packet)就会执行⼀次,
public void progress() {
System.out.println("&"); // 打印了两个 & & , 原因只要有数据, 第一次建立通道时, 就会打印一次
} // 无数据, 则不会建立通道
});
//3 实现流拷⻉
IOUtils.copyBytes(in, out, configuration); //默认关闭流选项是true,所以会自动关闭
//4 关流 可以再次关闭也可以不关了
}
240kb 打印了5次
第 6 节 NN与2NN
6.1 HDFS元数据管理机制
问题1:NameNode如何管理和存储元数据?
计算机中存储数据两种:内存或者是磁盘
元数据存储磁盘:存储磁盘⽆法⾯对客户端对元数据信息的任意的快速低延迟的响应,但是安全性⾼
元数据存储内存:元数据存放内存,可以⾼效的查询以及快速响应客户端的查询请求,数据保存在内存,如果断点,内存中的数据全部丢失。
解决⽅案:内存+磁盘;NameNode内存+FsImage的⽂件(磁盘)
新问题:磁盘和内存中元数据如何划分?
两个数据⼀模⼀样,还是两个数据合并到⼀起才是⼀份完整的数据呢?
⼀模⼀样:client如果对元数据进⾏增删改操作,需要保证两个数据的⼀致性。FsImage⽂件操作起来效率也不⾼。
两个合并=完整数据:NameNode引⼊了⼀个edits⽂件(⽇志⽂件:只能追加写⼊)edits⽂件记录的是client的增删改操作,
不再选择让NameNode把数据dump出来形成FsImage⽂件(这种操作是⽐较消耗资源)。
元数据管理流程图
第⼀阶段:NameNode启动
第⼀次启动NameNode格式化后,创建Fsimage和Edits⽂件。如果不是第⼀次启动,直接加载编辑⽇志和镜像⽂件到内存。
客户端对元数据进⾏增删改的请求。
NameNode记录操作⽇志,更新滚动⽇志。
NameNode在内存中对数据进⾏增删改。
第⼆阶段:Secondary NameNode⼯作
Secondary NameNode询问NameNode是否需要CheckPoint(检查点)。直接带回NameNode是否执⾏检查点操作结果。
Secondary NameNode请求执⾏CheckPoint。
NameNode滚动正在写的Edits⽇志。
将滚动前的编辑⽇志和镜像⽂件拷⻉到Secondary NameNode。
Secondary NameNode加载编辑⽇志和镜像⽂件到内存,并合并。
⽣成新的镜像⽂件fsimage.chkpoint。
拷⻉fsimage.chkpoint到NameNode。
NameNode将fsimage.chkpoint重新命名成fsimage。
再次进行相同操作时, 因为2NN本地已经有和NN中fsimage相同的文件, 所以只需要单独拉取edits文件即可
6.2 Fsimage与Edits⽂件解析
NameNode在执⾏格式化之后,会在/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current⽬录下产⽣如下⽂件
Fsimage⽂件:是namenode中关于元数据的镜像,⼀般称为检查点,这⾥包含了HDFS⽂件系统所有⽬录以及⽂件相关信息(Block数量,副本数量,权限等信息)
Edits⽂件 :存储了客户端对HDFS⽂件系统所有的更新操作记录,Client对HDFS⽂件系统所有的更新操作都会被记录到Edits⽂件中(不包括查询操作)
seen_txid:该⽂件是保存了⼀个数字,数字对应着最后⼀个Edits⽂件名的数字
VERSION:该⽂件记录namenode的⼀些版本号信息,⽐如:CusterId,namespaceID等
NameNode启动时会将Fsimage⽂件加载到内存中,同时也把之前未合并元数据的Edits⽂件加载,集合两个⽂件中的元数据这样保证了NameNode中的元数据是最新最全的。通俗点说就是NameNode启动时把Fsimage和Edits⽂件进⾏了合并
6.2.1 Fsimage⽂件内容
官⽅地址
https://hadoop.apache.org/docs/r2.9.2/hadoop-project-dist/hadoophdfs/HdfsImageViewer.html
1. 查看oiv和oev命令
[root@linux121 current]$ hdfs
oiv Offline Image Viewer View a Hadoop fsimage INPUTFILE using the specified
PROCESSOR,saving the results in OUTPUTFILE.oev Offline edits viewer Parse a Hadoop edits log file INPUT_FILE and save results in
OUTPUT_FILE
2. 基本语法
hdfs oiv -p ⽂件类型 -i 镜像⽂件 -o 转换后⽂件输出路径
3. 案例实操
[root@linux121 current]$ cd /opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current
[root@linux121 current]$ hdfs oiv -p XML -i fsimage_0000000000000000265 -o/opt/lagou/servers/fsimage.xml
[root@linux121 current]$ cat /opt/lagou/servers/fsimage.xml
<?xml version="1.0" encoding="utf-8"?>
<fsimage>
<version>
<layoutVersion>-63</layoutVersion>
<onDiskVersion>1</onDiskVersion>
<oivRevision>826afbeae31ca687bc2f8471dc841b66ed2c6704</oivRevision>
</version>
<NameSection>
<namespaceId>1600246680</namespaceId>
<genstampV1>1000</genstampV1>
<genstampV2>1031</genstampV2>
<genstampV1Limit>0</genstampV1Limit>
<lastAllocatedBlockId>1073741855</lastAllocatedBlockId>
<txid>322</txid>
</NameSection>
<INodeSection>
<lastInodeId>16460</lastInodeId>
<numInodes>38</numInodes>
<inode>
<id>16385</id>
<type>DIRECTORY</type>
<name/>
<mtime>1608803872604</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>9223372036854775807</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16386</id>
<type>DIRECTORY</type>
<name>test</name>
<mtime>1608721402078</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16387</id>
<type>DIRECTORY</type>
<name>input</name>
<mtime>1608721467236</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16388</id>
<type>FILE</type>
<name>test.txt</name>
<replication>3</replication>
<mtime>1608721467228</mtime>
<atime>1608721466811</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741825</id>
<genstamp>1001</genstamp>
<numBytes>11</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16389</id>
<type>DIRECTORY</type>
<name>wcinput</name>
<mtime>1608721739715</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16390</id>
<type>FILE</type>
<name>wc.txt</name>
<replication>3</replication>
<mtime>1608721739712</mtime>
<atime>1608721739585</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741826</id>
<genstamp>1002</genstamp>
<numBytes>75</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16391</id>
<type>DIRECTORY</type>
<name>tmp</name>
<mtime>1608723463398</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16392</id>
<type>DIRECTORY</type>
<name>hadoop-yarn</name>
<mtime>1608722073143</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16393</id>
<type>DIRECTORY</type>
<name>staging</name>
<mtime>1608722079920</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16394</id>
<type>DIRECTORY</type>
<name>root</name>
<mtime>1608722073143</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16395</id>
<type>DIRECTORY</type>
<name>.staging</name>
<mtime>1608723483885</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16401</id>
<type>DIRECTORY</type>
<name>history</name>
<mtime>1608722811506</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16402</id>
<type>DIRECTORY</type>
<name>done_intermediate</name>
<mtime>1608722079952</mtime>
<permission>root:supergroup:1777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16403</id>
<type>DIRECTORY</type>
<name>root</name>
<mtime>1608723519233</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16416</id>
<type>FILE</type>
<name>job_1608721096365_0001-1608722074684-root-word+count-1608722096309-1-1-SUCCEEDED-default-1608722083283.jhist</name>
<replication>3</replication>
<mtime>1608722096809</mtime>
<atime>1608722096374</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741835</id>
<genstamp>1011</genstamp>
<numBytes>33570</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16417</id>
<type>FILE</type>
<name>job_1608721096365_0001_conf.xml</name>
<replication>3</replication>
<mtime>1608722096865</mtime>
<atime>1608722096830</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741836</id>
<genstamp>1012</genstamp>
<numBytes>196027</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16418</id>
<type>DIRECTORY</type>
<name>done</name>
<mtime>1608722862958</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16419</id>
<type>DIRECTORY</type>
<name>2020</name>
<mtime>1608722862958</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16420</id>
<type>DIRECTORY</type>
<name>12</name>
<mtime>1608722862958</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16421</id>
<type>DIRECTORY</type>
<name>23</name>
<mtime>1608722862958</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16422</id>
<type>DIRECTORY</type>
<name>000000</name>
<mtime>1608723519233</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16428</id>
<type>DIRECTORY</type>
<name>logs</name>
<mtime>1608723463526</mtime>
<permission>root:root:1777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16429</id>
<type>DIRECTORY</type>
<name>root</name>
<mtime>1608723463549</mtime>
<permission>root:root:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16430</id>
<type>DIRECTORY</type>
<name>logs</name>
<mtime>1608723463571</mtime>
<permission>root:root:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16431</id>
<type>DIRECTORY</type>
<name>application_1608723229755_0001</name>
<mtime>1608723490418</mtime>
<permission>root:root:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16433</id>
<type>DIRECTORY</type>
<name>wcoutput</name>
<mtime>1608723482584</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16439</id>
<type>FILE</type>
<name>part-r-00000</name>
<replication>3</replication>
<mtime>1608723482412</mtime>
<atime>1608723482144</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741843</id>
<genstamp>1019</genstamp>
<numBytes>50</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16441</id>
<type>FILE</type>
<name>_SUCCESS</name>
<replication>3</replication>
<mtime>1608723482588</mtime>
<atime>1608723482584</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16444</id>
<type>FILE</type>
<name>job_1608723229755_0001-1608723461398-root-word+count-1608723482640-1-1-SUCCEEDED-default-1608723470652.jhist</name>
<replication>3</replication>
<mtime>1608723482716</mtime>
<atime>1608723482678</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741845</id>
<genstamp>1021</genstamp>
<numBytes>33569</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16445</id>
<type>FILE</type>
<name>job_1608723229755_0001_conf.xml</name>
<replication>3</replication>
<mtime>1608723482794</mtime>
<atime>1608723482732</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0777</permission>
<blocks>
<block>
<id>1073741846</id>
<genstamp>1022</genstamp>
<numBytes>196020</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16446</id>
<type>FILE</type>
<name>linux123_36439</name>
<replication>3</replication>
<mtime>1608723490414</mtime>
<atime>1608723490335</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:root:0777</permission>
<blocks>
<block>
<id>1073741847</id>
<genstamp>1023</genstamp>
<numBytes>106597</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16447</id>
<type>DIRECTORY</type>
<name>lagou</name>
<mtime>1608783476007</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16448</id>
<type>DIRECTORY</type>
<name>bigdata</name>
<mtime>1608783606376</mtime>
<permission>root:supergroup:0777</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16449</id>
<type>FILE</type>
<name>hadoop.txt</name>
<replication>3</replication>
<mtime>1608783745818</mtime>
<atime>1608783606318</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:root:0777</permission>
<blocks>
<block>
<id>1073741848</id>
<genstamp>1024</genstamp>
<numBytes>36</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16451</id>
<type>DIRECTORY</type>
<name>api_test1</name>
<mtime>1608797528444</mtime>
<permission>CH:supergroup:0755</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16452</id>
<type>DIRECTORY</type>
<name>api_test2</name>
<mtime>1608798259168</mtime>
<permission>root:supergroup:0755</permission>
<nsquota>-1</nsquota>
<dsquota>-1</dsquota>
</inode>
<inode>
<id>16456</id>
<type>FILE</type>
<name>b.txt</name>
<replication>1</replication>
<mtime>1608800028800</mtime>
<atime>1608800028734</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0644</permission>
<blocks>
<block>
<id>1073741852</id>
<genstamp>1028</genstamp>
<numBytes>11</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
<inode>
<id>16460</id>
<type>FILE</type>
<name>lagou.txt</name>
<replication>2</replication>
<mtime>1608803872719</mtime>
<atime>1608803872604</atime>
<preferredBlockSize>134217728</preferredBlockSize>
<permission>root:supergroup:0644</permission>
<blocks>
<block>
<id>1073741855</id>
<genstamp>1031</genstamp>
<numBytes>743232</numBytes>
</block>
</blocks>
<storagePolicyId>0</storagePolicyId>
</inode>
</INodeSection>
<INodeReferenceSection/>
<SnapshotSection>
<snapshotCounter>0</snapshotCounter>
<numSnapshots>0</numSnapshots>
</SnapshotSection>
<INodeDirectorySection>
<directory>
<parent>16385</parent>
<child>16451</child>
<child>16452</child>
<child>16456</child>
<child>16447</child>
<child>16460</child>
<child>16386</child>
<child>16391</child>
<child>16389</child>
<child>16433</child>
</directory>
<directory>
<parent>16386</parent>
<child>16387</child>
</directory>
<directory>
<parent>16387</parent>
<child>16388</child>
</directory>
<directory>
<parent>16389</parent>
<child>16390</child>
</directory>
<directory>
<parent>16391</parent>
<child>16392</child>
<child>16428</child>
</directory>
<directory>
<parent>16392</parent>
<child>16393</child>
</directory>
<directory>
<parent>16393</parent>
<child>16401</child>
<child>16394</child>
</directory>
<directory>
<parent>16394</parent>
<child>16395</child>
</directory>
<directory>
<parent>16401</parent>
<child>16418</child>
<child>16402</child>
</directory>
<directory>
<parent>16402</parent>
<child>16403</child>
</directory>
<directory>
<parent>16418</parent>
<child>16419</child>
</directory>
<directory>
<parent>16419</parent>
<child>16420</child>
</directory>
<directory>
<parent>16420</parent>
<child>16421</child>
</directory>
<directory>
<parent>16421</parent>
<child>16422</child>
</directory>
<directory>
<parent>16422</parent>
<child>16416</child>
<child>16417</child>
<child>16444</child>
<child>16445</child>
</directory>
<directory>
<parent>16428</parent>
<child>16429</child>
</directory>
<directory>
<parent>16429</parent>
<child>16430</child>
</directory>
<directory>
<parent>16430</parent>
<child>16431</child>
</directory>
<directory>
<parent>16431</parent>
<child>16446</child>
</directory>
<directory>
<parent>16433</parent>
<child>16441</child>
<child>16439</child>
</directory>
<directory>
<parent>16447</parent>
<child>16448</child>
</directory>
<directory>
<parent>16448</parent>
<child>16449</child>
</directory>
</INodeDirectorySection>
<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>
问题:Fsimage中为什么没有记录块所对应DataNode?
在内存元数据中,有记录块所对应的dn信息, 但是fsimage中剔除了这个信息, 在HDFS集群启动后,会加载image和edits文件 , block对应的dn信息都没有记录 ,
集群启动时会有一个安全模式, NameNode要求DataNode上报数据块信息补全元数据,并间隔⼀段时间后再次上报。
6.2.2 Edits⽂件内容
1. 基本语法
hdfs oev -p ⽂件类型 -i编辑⽇志 -o 转换后⽂件输出路径
2. 案例实操
[root@linux121 current]$ hdfs oev -p XML -i edits_0000000000000000266-0000000000000000267 -o /opt/lagou/servers/hadoop-2.9.2/edits.xml
[root@linux121 current]$ cat /opt/lagou/servers/hadoop-2.9.2/edits.xml
<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
<EDITS_VERSION>-63</EDITS_VERSION>
<RECORD>
<OPCODE>OP_START_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>310</TXID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>311</TXID>
<LENGTH>0</LENGTH>
<INODEID>16459</INODEID>
<PATH>/lagou.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1608803708666</MTIME>
<ATIME>1608803708666</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_-393440837_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.80.1</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<RPC_CLIENTID>e709ee8a-4a4a-426e-a6a5-1521da6d1045</RPC_CLIENTID>
<RPC_CALLID>0</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
<DATA>
<TXID>312</TXID>
<BLOCK_ID>1073741854</BLOCK_ID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
<DATA>
<TXID>313</TXID>
<GENSTAMPV2>1030</GENSTAMPV2>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCK</OPCODE>
<DATA>
<TXID>314</TXID>
<PATH>/lagou.txt</PATH>
<BLOCK>
<BLOCK_ID>1073741854</BLOCK_ID>
<NUM_BYTES>0</NUM_BYTES>
<GENSTAMP>1030</GENSTAMP>
</BLOCK>
<RPC_CLIENTID></RPC_CLIENTID>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_CLOSE</OPCODE>
<DATA>
<TXID>315</TXID>
<LENGTH>0</LENGTH>
<INODEID>0</INODEID>
<PATH>/lagou.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1608803708775</MTIME>
<ATIME>1608803708666</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME></CLIENT_NAME>
<CLIENT_MACHINE></CLIENT_MACHINE>
<OVERWRITE>false</OVERWRITE>
<BLOCK>
<BLOCK_ID>1073741854</BLOCK_ID>
<NUM_BYTES>7742</NUM_BYTES>
<GENSTAMP>1030</GENSTAMP>
</BLOCK>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_DELETE</OPCODE>
<DATA>
<TXID>316</TXID>
<LENGTH>0</LENGTH>
<PATH>/lagou.txt</PATH>
<TIMESTAMP>1608803864839</TIMESTAMP>
<RPC_CLIENTID></RPC_CLIENTID>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD</OPCODE>
<DATA>
<TXID>317</TXID>
<LENGTH>0</LENGTH>
<INODEID>16460</INODEID>
<PATH>/lagou.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1608803872604</MTIME>
<ATIME>1608803872604</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME>DFSClient_NONMAPREDUCE_1954272539_1</CLIENT_NAME>
<CLIENT_MACHINE>192.168.80.1</CLIENT_MACHINE>
<OVERWRITE>true</OVERWRITE>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
<RPC_CLIENTID>46edb4c8-193c-4079-a907-2d30eaa74a26</RPC_CLIENTID>
<RPC_CALLID>0</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
<DATA>
<TXID>318</TXID>
<BLOCK_ID>1073741855</BLOCK_ID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
<DATA>
<TXID>319</TXID>
<GENSTAMPV2>1031</GENSTAMPV2>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_ADD_BLOCK</OPCODE>
<DATA>
<TXID>320</TXID>
<PATH>/lagou.txt</PATH>
<BLOCK>
<BLOCK_ID>1073741855</BLOCK_ID>
<NUM_BYTES>0</NUM_BYTES>
<GENSTAMP>1031</GENSTAMP>
</BLOCK>
<RPC_CLIENTID></RPC_CLIENTID>
<RPC_CALLID>-2</RPC_CALLID>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_CLOSE</OPCODE>
<DATA>
<TXID>321</TXID>
<LENGTH>0</LENGTH>
<INODEID>0</INODEID>
<PATH>/lagou.txt</PATH>
<REPLICATION>2</REPLICATION>
<MTIME>1608803872719</MTIME>
<ATIME>1608803872604</ATIME>
<BLOCKSIZE>134217728</BLOCKSIZE>
<CLIENT_NAME></CLIENT_NAME>
<CLIENT_MACHINE></CLIENT_MACHINE>
<OVERWRITE>false</OVERWRITE>
<BLOCK>
<BLOCK_ID>1073741855</BLOCK_ID>
<NUM_BYTES>743232</NUM_BYTES>
<GENSTAMP>1031</GENSTAMP>
</BLOCK>
<PERMISSION_STATUS>
<USERNAME>root</USERNAME>
<GROUPNAME>supergroup</GROUPNAME>
<MODE>420</MODE>
</PERMISSION_STATUS>
</DATA>
</RECORD>
<RECORD>
<OPCODE>OP_END_LOG_SEGMENT</OPCODE>
<DATA>
<TXID>322</TXID>
</DATA>
</RECORD>
</EDITS>
备注:Edits中只记录了更新相关的操作,查询或者下载⽂件并不会记录在内!!
问题:NameNode启动时如何确定加载哪些Edits⽂件呢?
需要借助fsimage⽂件最后数字编码,来确定哪些edits之前是没有合并到fsimage中,启动时只需要加载那些未合并的edits⽂件即可。
6.3 checkpoint周期
hdfs-default.xml
<!-- 定时⼀⼩时 --> <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 >
第 7 节 NN故障处理
NameNode故障后,HDFS集群就⽆法正常⼯作,因为HDFS⽂件系统的元数据需要由NameNode来管理维护并与Client交互,如果元数据出现损坏和丢失同样会导致NameNode⽆法正常⼯作进⽽HDFS⽂件系统⽆法正常对外提供服务。
如果元数据出现丢失损坏如何恢复呢?
1. 将2NN的元数据拷⻉到NN的节点下
此种⽅式会存在元数据的丢失。checkpoint之间的数据会丢失
2. 搭建HDFS的HA(high availability ⾼可⽤)集群,解决NN的单点故障问题!!(借助Zookeeper实现HA,⼀个Active的NameNode,⼀个是Standby的NameNode)
第 8 节 Hadoop的限额与归档以及集群安全模式
HDFS⽂件限额配置
HDFS⽂件的限额配置允许我们以⽂件⼤⼩或者⽂件个数来限制我们在某个⽬录下上传的⽂件数量或者⽂件内容总量,以便达到我们类似百度⽹盘⽹盘等限制每个⽤户允许上传的最⼤的⽂件的量
数量限额
#查看hdfs管理命令
hdfs dfsadmin -help#创建hdfs⽂件夹
hdfs dfs -mkdir -p /user/root/lagou# 给该⽂件夹下⾯设置最多上传
hdfs dfsadmin -setQuota 2 /user/root/lagou两个⽂件,上传⽂件,发现只能上传⼀个⽂件
# 清除⽂件数量限制
hdfs dfsadmin -clrQuota /user/root/lagou
空间⼤⼩限额
# 限制空间⼤⼩4KB
hdfs dfsadmin -setSpaceQuota 4k /user/root/lagou#上传超过4Kb的⽂件⼤⼩, 提示⽂件超过限额
hdfs dfs -put /export/softwares/xxx.tar.gz /user/root/lagou#清除空间限额
hdfs dfsadmin -clrSpaceQuota /user/root/lagou#查看hdfs⽂件限额数量
hdfs dfs -count -q -h /user/root/lagou
HDFS的安全模式
安全模式是HDFS所处的⼀种特殊状态,在这种状态下,⽂件系统只接受读数据请求,⽽不接受删除、修改等变更请求。在NameNode主节点启动时,HDFS⾸先进⼊安全模式,DataNode在启动的时候会向NameNode汇报可⽤的block等状态,当整个系统达到安全标准时,HDFS⾃动离开安全模式。如果HDFS出于安全模式下,则⽂件block不能进⾏任何的副本复制操作,因此达到最⼩的副本数量要求是基于DataNode启动时的状态来判定的,启动时不会再做任何复制(从⽽达到最⼩副本数量要求),HDFS集群刚启动的时候,默认30S钟的时间是出于安全期的,只有过了30S之后,集群脱离了安全期,然后才可以对集群进⾏操作。
hdfs dfsadmin -safemode
Hadoop归档技术
主要解决HDFS集群存在⼤量⼩⽂件的问题!!
由于⼤量⼩⽂件会占⽤NameNode的内存,因此对于HDFS来说存储⼤量⼩⽂件造成NameNode内存资源的浪费!
Hadoop存档⽂件HAR⽂件,是⼀个更⾼效的⽂件存档⼯具,HAR⽂件是由⼀组⽂件通过archive⼯具创建⽽来,在减少了NameNode的内存使⽤的同时,可以对⽂件进⾏透明的访问,通俗来说就是HAR⽂件对NameNode来说是⼀个⽂件减少了内存的浪费,对于实际操作处理⽂件依然是⼀个⼀个独⽴的⽂件。
案例
1. 归档命令查询
[root@linux121 hadoop-2.9.2]$ hadoop archive -help
2. 归档⽂件
把/user/lagou/input⽬录⾥⾯的所有⽂件归档成⼀个叫input.har的归档⽂件,并把归档后⽂件存储到/user/lagou/output路径下。
[root@linux121 hadoop-2.9.2]$ bin/hadoop archive -archiveName input.har –p /user/root/input /user/root/output
3. 查看归档
[root@linux121 hadoop-2.9.2]$ hadoop fs -lsr /user/root/output/input.har
[root@linux121 hadoop-2.9.2]$ hadoop fs -lsrhar:///user/root/output/input.har
4. 解归档⽂件
[root@linux121 hadoop-2.9.2]$ hadoop fs -cp har:/// user/root/output/input.har/* /user/root