HDFS(分布式文件系统)
1 HDFS架构
HDFS (Hadoop Distributed File System) Hadoop分布式文件系统。
作用:
解决海量数据存储问题—分布式文件系统(多台计算机存储)
突破单体服务器的存储能力。
在学习HDFS的使用前,我们先来了解下HDFS的架构和相关的概念。无论使用何种技术,大规模数据存储都要解决以下几个核心问题:
- 数据存储容量的问题 :大数据要解决的是数以PB计的数据计算问题,而一般的服务器磁盘容量通常以TB为单位,那么如何存储这么大规模的数据?
- 数据读写速度的问题:一般磁盘的连续读写速度为几十MB,以这样的速度,几十PB的数据恐怕要读写到天荒地老。
- 数据可靠性的问题:磁盘大约是计算机设备中最易损坏的硬件了,通常情况一块磁盘使用寿命大概是一年,如果磁盘损坏了,怎么保证数据不丢失?
HDFS的架构是围绕这几方面问题的解决展开设计。
1.1 数据块和副本
1.1.1 数据块
HDFS上存储的大文件通常无法在一个节点上完整存储,就需要将文件拆分成多个数据块(block)分散存储,默认是128MB。其实单一磁盘上的文件系统,也是将文件划分成块大小的多个分块,但是和HDFS的块相比要小的多(4KB)。与面向单一磁盘的文件系统不同的是,HDFS的块会被存放到大数据机器集群上不同的机器。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ed00imYR-1630554804591)(HDFS笔记.assets/image-20210216103319198.png)]
HDFS的块为什么这么大?
HDFS的块默认为128MB是为了匹配现有的硬件的传输速度。现有的服务器机房局域网网络千兆带宽=125MB/s,磁盘读写速度100~300MB/s
block过小:块的数量变多,增加了文件的寻址次数,也就增加了文件整体的寻址开销。
block过大:会导致单个block读取时间过长,影响该部分数据的处理速度。且增加了单个块传输的失败几率,重试成本过高。以后随着新一代硬件传输速度的提升,块的大小会被设置的更大。
说明:和单一磁盘文件系统对于块的处理有一点不同,单一磁盘文件系统中小于1个块大小的文件也会占用1个块的磁盘空间,而HDFS中小于1个块大小的文件不会占据整个块的空间(例如1MB的文件存储在128MB的块中,只会占用1MB的磁盘空间)。
1.1.2 副本
由于 Hadoop 被设计运行在廉价的机器上,这意味着硬件是不可靠的,为了保证容错性,HDFS 提供了数据复制机制。HDFS 将每一个文件存储为一系列块的同时,每个块由多个副本来保证容错,块的大小和复制因子可以自行配置(默认情况下,块大小是 128M,默认复制因子是 3)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tDZVngy6-1630554804594)(HDFS笔记.assets/image-20210216103807178.png)]
作用:防止因为机器的单点故障,导致数据丢失。
实战参数:一般block的replication就是3个。
1.2 NameNode和DataNode
文件在文件系统中存储有2部分信息:
- 元数据:保存文件的描述信息(类型、权限、所有者、大小等等)
- 数据:文件中真正的数据部分(对应着数据块)
在HDFS集群中有专门管理元数据的NameNode节点和保存数据块的DataNode节点。HDFS 遵循主/从架构,HDFS集群节点由单个 NameNode(NN) 和多个 DataNode(DN) 组成:
-
NameNode :
-
基于内存管理文件的元数据(文件路径、权限信息、大小、副本数、数据块、数据块DN列表)
张3.avi -rwxrwxrwx root root 500M 3 [blk1,blk2,…]
-
管理着集群中所有DataNode节点信息,是集群的管理者(master)
datanode12 ip地址 磁盘容量 磁盘使用情况
datanode13 ip地址 磁盘容量 磁盘使用情况目的:掌握datanode健康状况,了解磁盘容量,数据分布的负载均衡。
均衡使用datanode的磁盘空间。 集合多个datanode服务器的网络带宽,提高数据传输速度。
-
-
DataNode:
- 保存实际的文件数据(文件切分后的数据块),并负责处理client发起的数据读写请求
- 是HDFS集群的从节点(Slave)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uzhIXdUz-1630554804595)(HDFS笔记.assets/image-20210216112649479.png)]
1.3 心跳和块状态报告
在集群环境下,因为网络割裂或者DataNode宕机会导致一部分Datanode跟Namenode失去联系。NameNode如何获取最新在线的DataNode节点信息?
解决方案:心跳机制(heartBeat)
每个Datanode节点周期性(3s)地向Namenode发送心跳信号。Namenode通过心跳信号的缺失来检测这一情况,并将这些近期(10min)不再发送心跳信号的Datanode标记为宕机,不会再将新的IO请求发给它们。
因为HDFS运行在廉价的机器上,DataNode上的数据块在长时间使用后很可能会损坏。NameNode如何获取到最新的数据块状态呢?
解决方案:块状态报告(blockreport)
DataNode会定期上报datanode中的存储的block的信息到Namenode,如果上报的信息中没有包含某个块的信息,则说明该块已经损坏。
示例:dn1中存储blk1、blk2一共2个块,上报块状态时如果发现blk2已经损坏,只会上报blk1的块信息,NameNode没有收到blk2的信息,则认为blk2已经损坏
说明:NameNode中并不会存储节点信息和块的存储信息,在HDFS启动后由DataNode通过心跳和块状态报告获取。
那么,还有一个问题:DataNode是如何判断一个块是否损坏?
解决方案:校验和(CheckSum、数字指纹)
DataNode在存储数据块的时候会同时存储其checksum。datanode定期,计算本节点存储的block的checksum,判断是否和之前的checksum保持一致。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-voPzY9RN-1630554804597)(HDFS笔记.assets/image-20210216120702640.png)]
1.4 文件的写流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TiFOKKoj-1630554804598)(HDFS笔记.assets/image-20210216123201457.png)]
写流程:
- Client首先将要存储的数据切分成若干块,然后向NameNode发送存储请求
- NameNode检查权限、存储文件是否已存在等信息,确认无误后返回允许存储的响应,这个响应还包括第一个Block要存放的DataNode列表的信息(比如DN1、DN3、DN4)。
- Client得到NameNode的响应,打开文件输出流,向第一个DataNode请求打开管道,DN1接受的信息后继续通知DN3,DN3接受到DN1的信息后通知DN4,DN4接受到信息后确认没有更多副本了,向DN3返回响应信息,DN3获取到DN4的响应后向DN1返回响应,DN1得到响应后向Clinet返回响应
- Clinet获得响应后,确认pipeline(管线,管线上每个节点都能收到相同的数据流)已开通,开始写入数据。
- Client在确认block1完成传输后,向NameNode发送请求,确认block1已存入,NN更新自己的元数据,并返回block2的存储地址
- 重复,直到所有block都存入。
1.5 文件的读流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dWW35OXz-1630554804599)(HDFS笔记.assets/image-20210216125637278.png)]
读流程:
- Client访问NameNode,查询元数据信息,获得这个文件的数据块和每个数据块的DN列表
- 客户端Client会选取离客户端最近的DataNode来读取block;。
- 读取完当前block的数据后,关闭当前的DataNode链接,并为读取下一个block寻找最佳的DataNode;。
- 客户端接收数据后,先在本地缓存,然后写入目标文件。
2 安装(伪分布式)
软件下载地址:点击这里
-
集群规划(在1台机器上搭建伪分布式)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3cyuCOQ3-1630554804600)(HDFS笔记.assets/image-20210803220914711.png)]
-
服务器环境准备
0. 克隆机器 1. 修改ip vi /etc/sysconfig/network-scripts/ifcfg-ens33 2. 设置hostname hostnamectl set-hostname hadoop10 3. 域名映射 vi /etc/hosts 4. 关闭防火墙 systemctl stop firewalld systemctl disable firewalld 5. 安装JDK tar xzvf jdk1.8-xxx.tar.gz -C /opt/installs/ 6. 并配置环境变量 vi /etc/profile export JAVA_HOME=/opt/installs/jdk1.8/ export PATH=$PATH:/opt/installs/jdk1.8/bin/ export classpath=. 7. 加载配置 source /etc/profile
-
安装HDFS(Hadoop中包含HDFS)
0. 上传hadoop安装包到/opt/modules 1. 解压缩 [root@hadoop10 modules]# tar xzvf hadoop-2.9.2.tar.gz -C /opt/installs/ 2. 配置环境变量 vi /etc/profile 编辑内容如下: export HADOOP_HOME=/opt/installs/hadoop-2.9.2 export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin 3. 重新加载配置 source /etc/profile
hadoop目录结构
yum install -y tree #安装tree工具 #通过tree查看Hadoop目录结构 [root@hadoop10 ~]# tree -L 1 /opt/installs/hadoop-2.9.2/ /opt/installs/hadoop-2.9.2/ ├── bin # hadoop客户端操作相关的脚本程序,hdfs、hadoop、yarn ├── etc # 配置文件目录 ├── include # C语言编写的程序,无需关注 ├── lib # 使用C语言编写的native实现,无需关注 ├── libexec # hadoop运行时,加载配置的脚本 ├── logs # 系统运行日志目录,排查故障!初始安装时没有,运行后就会自动生成 ├── LICENSE.txt ├── NOTICE.txt ├── README.txt ├── sbin # hadoop服务端操作相关的脚本,常见的比如:启动或关闭服务 └── share # hadoop运行的依赖jar包
-
初始化配置文件(hadoop-2.9.2/etc/hadoop/)
hadoop-env.sh — hadoop环境配置(jdk) core-site.xml — hadoop核心配置文件 hdfs-site.xml — HDFS的个性化配置文件 副本因子 slaves — 在哪个节点启动datanode
-
haddop-env.sh配置jdk环境变量
将export JAVA_HOME=${JAVA_HOME} 修改为 export JAVA_HOME=/opt/installs/jdk1.8.0_291
-
core-site.xml 配置服务访问地址和数据保存位置
<configuration> <!-- 在这里添加如下配置--> <!-- 配置hdfs入口,本质上就是NameNode节点所在机器的ip和服务端口号--> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop10:9000</value> </property> <!-- 配置数据保存的位置,需要在hadoop的根目录下新建data目录 --> <property> <name>hadoop.tmp.dir</name> <value>/opt/installs/hadoop-2.9.2/data</value> </property> </configuration>
-
hdfs-site.xml 配置副本个数
<configuration> <!-- 添加如下配置--> <!-- 设置数据块副本数量,伪分布式DataNode只有1个,所以副本量配置为1--> <property> <name>dfs.replication</name> <value>1</value> </property> </configuration>
-
slaves 配置slave(也就是DataNode的节点ip)
hadoop10 #配置从机DataNode的ip,如果DataNode有多个就配置多个(多个ip换行分隔)
-
-
格式化HDFS(第1次安装HDFS格式化文件系统)
一旦hadoop配置启动失败,清空data下的文件,再重新格式化。 hdfs namenode -format #初始化namenode和datanode存放数据的目录
-
启动HDFS
# 启动hdfs,注意:启动过程中需要多次输入密码 start-dfs.sh # 关闭hdfs,注意:关闭过程中也需要多次输入密码 stop-dfs.sh 日后可以通过配置免密登录解决启动和关闭过程多次输入密码的繁琐问题
-
验证
# 查看hdfs进程,必须要有以下的进程 [root@hadoop10 installs]# jps 2225 NameNode # master namenode主机 4245 Jps 2509 SecondaryNameNode 2350 DataNode # slave datanode从机
# 查看hdfsWeb服务,注意在物理机上也需要配置域名映射才可以直接通过域名:hadoop10访问 1. 查看namenode的web服务 http://hadoop10:50070 2. 查看datanode的Web服务 http://hadoop10:50075
3 搭建知识补充
-
日志查看(查看hdfs运行异常)
hadoop-2.9.2/logs/下保存着hadoop相关的运行日志 # namenode启动运行日志 hadoop-用户名-namenode-主机名.log # datanode启动日志 hadoop-用户名-datanode-主机名.log
-
HDFS(配置错误修正)
# 1. 关闭启动的hdfs程序(NN DN) stop-dfs.sh # 2. 修改错误的配置文件。 # 3. data目录清空,重新格式化 hdfs namenode -format 场景: 格式化或者启动hadoop失败,则说明配置有问题 说明: hadoop/data文件夹 作用: 保存datanode和namenode持久化的数据。 时机: 1. 格式化hdfs namenode -format 会初始化该目录下的文件。 2. hdfs运行期间产生的数据,会操作该目录中的数据。 必要操作:删除格式化或者启动数据保存的文件目录。
-
Web界面
NameNode的web管理器地址:http://ip:50070
在NameNode管理页面有2个常用功能:查看DataNode信息和管理文件元数据
-
查看DataNode信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ZbnlPQz-1630554804601)(HDFS笔记.assets/image-20210216152441650.png)]
-
管理文件元数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xE8y4wuH-1630554804602)(HDFS笔记.assets/image-20210216152609919.png)]
4 HDFS客户端
要使用HDFS管理文件,需要使用Client操作HDFS。而我们通过Client主要完成如下的操作:
- 上传文件
- 下载文件
- 删除文件
- 修改文件名(不能直接修改文件内容,可以通过2次覆盖完成修改)
4.1 HDFS命令
通过内置的hdfs命令使用Client。
-
命令所在的目录
hadoop安装目录/bin/hdfs
-
HDFS文件系统结构
和Linux目录结构相似
-
命令格式
hdfs dfs -命令 -参数
4.2 常用命令
命令 | 含义 | 示例代码 |
---|---|---|
hdfs dfs -ls [-R] hdfs文件路径 | 查看文件元数据信息 | hdfs dfs -ls / |
hdfs dfs -mkdir -p /目录a/目录b | 新建文件夹,如果父目录不存在则添加-p参数 | hdfs dfs -mkdir -p /baizhi/file |
hdfs dfs -put linux文件路径 hdfs文件路径 | 文件上传 | hdfs dfs -put /opt/models/jdk /baizhi |
hdfs dfs -get hdfs文件路径 linux文件路径 | 文件下载 | hdfs dfs -get /baizhi/jdk1.8 /opt |
hdfs dfs -cat hdfs文档路径 | 查看文件内容 | hdfs dfs -cat /baizhi/Test.java |
hdfs dfs -rm hdfs文件路径 | 删除文件 | hdfs dfs -rm /baizhi/Test.java |
hdfs dfs -rm -r hdfs文件夹 | 删除文件夹 | hdfs dfs -rm -r /baizhi |
hdfs dfs -chmod [-R] 权限运算值 hdfs文件 hdfs dfs -chmod [-R] u+x hdfs文件路径 | 修改hdfs文件权限 | hdfs dfs -chmod o+w /baizhi |
hdfs dfs -appendToFile linux本地A文件 HDFS远程B文件 | 将A文件内容追加到HDFS的B文件的末尾。 | hdfs dfs -appendToFile /etc/profile /Test1.java |
hdfs dfs -mv /hdfs/demo1/wordcount1.log /hdfs/demo2 | 移动HDFS文件系统内部文件 | hdfs dfs -mv /hdfs/demo1/wordcount1.log /hdfs/demo2 |
hdfs dfs -getmerge HDFS的文件目录 linux本地文件 | 将HDFS中的目录下多个文件,合并后下载本地 | hdfs dfs -getmerge /config/*.xml /hello.xml |
hdfs dfs -copyFromLocal linux文件路径 hdfs目录 | 文件上传 | hdfs dfs -copyFromLocal jdk-8u191-linux-x64.rpm / |
hdfs dfs -copyToLocal hdfs文件路径 linux本地文件路径 | 文件下载 | hdfs dfs -copyToLocal /jdk-8u191-linux-x64.rpm /root/ |
hdfs dfs -moveToLocal HDFS文件路径 linux文件路径(当前版本还没有实现) | HDFS文件移动到客户端本地(下载+删除远程) | |
hdfs dfs -moveFromLocal linux文件路径 hdfs文件路径(可以用) | 客户端文件移动到HDFS中(上传+删除本地) | hdfs dfs -moveFromLocal jdk-8u191-linux-x64.rpm /dir1 |
# 场景
大量10w小文件在HDFS存储,每个文件1kb,总大小,100MB.
HDFS保存多少元数据:
10w个文件描述信息
10w个block的位置信息
HDFS保存多少Block:
10w*3个block.
# 问题:
产生大量的block描述信息,大量的文件元数据,占用大量的NameNode内存空间,。
# 解决:
1. 使用HDFS命令合并下载本地。 -getmerge
2. 将合并后的文件上传即可。
3. 原始的小文件删除了。
5 Java操作HDFS
除了可以通过命令行Client操作HDFS,还可以通过Java API操作HDFS。
5.1 环境搭建
在windows上需要准备HDFS专有开发环境。
-
解压缩 hadoop2.9.2的软件到windows中(路径不能有中文,不能有空格)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yXcALOg4-1630554804602)(HDFS笔记.assets/image-20210216174148340.png)]
注意:要以管理员身份解压缩
-
拷贝bin路径下,替换客户端工具。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZEAlGLCt-1630554804603)(HDFS笔记.assets/image-20210216175010272.png)]
-
在windows中配置hadoop环境变量
HADOOP_HOME=hadoop安装路径 PATH=hadoop安装路径/bin
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwBy5Uue-1630554804604)(HDFS笔记.assets/image-20210216182804994.png)]
-
如果IDEA或者Eclipse已经启动,需要重启下开发工具
5.2 入门
API | 含义作用 |
---|---|
Configuration | 配置信息,封装操作hdfs的配置文件信息 |
FileSystem | HDFS分布式文件系统工具,操作HDFS中的文件 |
Path | 操作的文件路径 |
-
添加log4j.properties配置文件和依赖
<dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
-
编码
package com.baizhi.test; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.junit.Test; import java.io.IOException; public class HDFSTest { @Test public void testCopyFormLocalFile() throws IOException { //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS","hdfs://192.168.146.10:9000"); configuration.set("dfs.replication","1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS fs.copyFromLocalFile(new Path("E:/test.mp4"), new Path("/baizhi/file")); //4 释放资源 fs.close(); } }
常见异常:
Caused by: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.AccessControlException): Permission denied: user=Xsy, access=WRITE, inode="/baizhi/file":root:supergroup:drwxr-xr-x
解决方案:
为hdfs文件夹/baizhi/file添加写权限
hdfs dfs -chmod 777 /baizhi/file
5.3 常见API操作
-
上传
@Test public void testCopyFormLocalFile() throws IOException { //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS","hdfs://192.168.146.10:9000"); configuration.set("dfs.replication","1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS fs.copyFromLocalFile(new Path("E:/test.mp4"), new Path("/data/file/test.mp4")); //4 释放资源 fs.close(); }
-
下载
@Test public void testCopyToLocalFile() throws IOException{ //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS","hdfs://192.168.146.10:9000"); configuration.set("dfs.replication","1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS fs.copyToLocalFile(new Path("/baizhi/file/test.mp4"), new Path("E:/test2.mp4")); //4 释放资源 fs.close(); }
-
删除
@Test public void testDelete() throws IOException{ //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS", "hdfs://192.168.146.10:9000"); configuration.set("dfs.replication", "1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS /** 参数1:远端hdfs的文件路径 参数2:是否递归删除,如果删除的是文件夹设置为false,删除无法递归则会抛出异常 如果是文件,无论是true|false都可以 返回值:是否删除成功 */ boolean deleteOk = fs.delete(new Path("/baizhi/file/test.mp4"), true); System.out.println("deleteOk = " + deleteOk); //4 释放资源 fs.close(); }
-
文件追加内容
@Test public void testAppend() throws IOException { //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS", "hdfs://192.168.146.10:9000"); configuration.set("dfs.replication", "1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS FSDataOutputStream out = fs.append(new Path("/baizhi/file/test.txt")); out.write("hello world".getBytes()); out.close(); //4 释放资源 fs.close(); }
-
查看目录组成
@Test public void testListStatus() throws IOException{ //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS", "hdfs://192.168.146.10:9000"); configuration.set("dfs.replication", "1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS FileStatus[] fileStatuses = fs.listStatus(new Path("/baizhi/file")); for (FileStatus status : fileStatuses) { //获取文件路径 Path path = status.getPath(); System.out.println("path = " + path); //是否是目录 boolean directory = status.isDirectory(); System.out.println("directory = " + directory); //获取文件权限 FsPermission permission = status.getPermission(); System.out.println("permission = " + permission); //获取数据块副本数 short replication = status.getReplication(); System.out.println("replication = " + replication); //获取上次修改时间 long modificationTime = status.getModificationTime(); System.out.println("modificationTime = " + modificationTime); //获取文件大小,单位字节 long len = status.getLen(); System.out.println("len = " + len); } //4 释放资源 fs.close(); }
-
读取文件信息
@Test public void testListFiles() throws IOException{ //1 初始化配置 Configuration configuration = new Configuration(); configuration.set("fs.defaultFS", "hdfs://192.168.146.10:9000"); configuration.set("dfs.replication", "1"); //2 获取操作HDFS的工具 FileSystem fs = FileSystem.get(configuration); //3 操作HDFS /** * 功能:递归获得目录下的所有文件(不包含文件夹)的元数据信息,相当于hdfs的ls命令 * listFiles参数1:要查看的目录 * listFiles参数2:是否递归 -R */ RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true); while(files.hasNext()){ //迭代获得每个file元数据 LocatedFileStatus file = files.next(); //1. 获得文件路径 Path path = file.getPath(); System.out.println("path = " + path); //2. 获得文件权限 FsPermission permission = file.getPermission(); System.out.println("permission = " + permission); //3. 获得文件副本数 short replication = file.getReplication(); System.out.println("replication = " + replication); //4. 获得文件修改时间,long的时间戳 long modificationTime = file.getModificationTime(); System.out.println("modificationTime = " + modificationTime); //5. 获得文件大小,单位B long len = file.getLen(); System.out.println("len = " + len); //6. 获得block的切片分布信息 BlockLocation[] blockLocations = file.getBlockLocations(); System.out.println("blockLocations = " + Arrays.toString(blockLocations)); } //4 释放资源 fs.close(); }
6 HDFS原理相关
6.1 Trash 回收站
回收站:主要用来存放用户临时删除的文档资料,存放在回收站的文件可以恢复,避免用户误删数据。
HDFS为了规避由于用户的误操作,导致的数据删除丢失,用户可以在构建HDFS的时候,配置HDFS的垃 圾回收功能。所谓的垃圾回收,本质上是在用户删除文件的时候,系统并不会立即删除文件,仅仅是将 文件移动到垃圾回收的目录。并配置过期时间,一旦超过该时间,系统会删除该文件,用户需要在 到期之前,将回收站的文件移出垃圾站,即可避免删除。
配置core-site.xml,开启垃圾回收功能
<!--开启垃圾回收,需要在core-site.xml中添加如下配置,然后重启hdfs即可-->
<!--垃圾回收,1440分钟 == 1天-->
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
验证回收站功能是否开启成功
#删除一个文件
hdfs dfs -rm /baizhi/file/test.txt
#日志信息
21/02/16 21:37:47 INFO fs.TrashPolicyDefault: Moved: 'hdfs://hadoop10:9000/baizhi/file/test.txt' to trash at: hdfs://hadoop10:9000/user/root/.Trash/Current/baizhi/file/test.txt
还原文件
# 恢复回收站数据(本质上就是移动文件)
hdfs dfs -mv /user/root/.Trash/Current/baizhi/file/test.txt /baizhi/file/
6.2 NameNode持久化
NameNode中的元数据是保存在内存中的,如果NameNode宕机,导致内存中的文件元数据丢失怎么办?NameNode有一套持久化机制避免数据丢失。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iajRuVXT-1630554804604)(HDFS笔记.assets/image-20210216224636772.png)]
持久化方式分析:
-
日志持久化
NameNode会将每一个增删改的命令记录到日志文件中,然后再修改内存中的元数据
特点:
- 记录最新操作,数据完整性高 --持久化角度
- 如果操作积累的比较多,文件比较大,数据恢复时比较慢。–数据恢复角度
-
快照持久化
fsimage是二进制的序列化文件,是对内存中元数据的快照,可以跨平台,恢复速度快。
特点:
- 数据不及时,完整性低。–持久化角度
- 空间占用小,数据恢复速度快。–数据恢复角度
NameNode持久化思路:
- Client发起增删改的操作请求
- 将增删改操作记录到edits log文件中
- 在内存中做元数据的增删改操作
- 同时edits log的内容会不断的定时合并到fsimage中(具体怎么合并,就需要SNN的辅助了)
- 合并的同时,生成新的edits log文件(避免edits log积累操作过多,文件过大。这个时候fsimage已经记录了原edits log文件的操作,也没必要保存原edits log的操作记录了)
总结:NameNode的持久化文件由edits log
文件和 fsimage
文件构成:edits log记录某个时间节点后的操作记录,fsimage记录某个时间节点前的元数据信息,edits log + fsimage 2者合在一起等同于NameNode中内存里的元数据。
6.3 SecondaryNameNode和检查点
SecondaryNameNode:负责合并edit log和fsimage。
由于2种持久化方式各自的特点,HDFS会混合使用2种方式:edits log记录最新的操作,定期合并到fsimage中。由于在HDFS架构中NameNode是单节点的,为避免合并操作影响NameNode本身正常的服务,NameNode本身不会执行edits log和fsimage的合并,而是由SecondaryNameNode负责合并。
SecondaryNameNode的合并工作流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DyvRXba-1630554804605)(HDFS笔记.assets/image-20210216232448682.png)]
- 对原edits文件重命名保存,并创建一个新的日志文件(新日志文件记录合并过程中的操作)
- 将eidts文件和fsimage复制到SNN上
- SNN将fsimage的数据读取到内存,然后应用edits记录的操作,得到合并后的fsimage.ckpt
- 将合并后的fsimage.ckpt复制到NN,重命名为fsimage并替换原有的fsimage
注意:如果在合并过程中NameNode损坏,那么,丢失了在合并过程中产生的新的edits,因此namenode失效时,难免会丢失部分元数据。
CheckPoint:SNN执行一次合并的过程,称之为检查点。
CheckPoint的触发时机
# 每1分钟检查一次触发条件。(SNN每隔1分钟,访问一次NN),如果检查发现满足以下任一条件即触发检查点
- 每隔1小时触发一次checkPoint
- 每100w次操作,触发一次checkpoint
可以在hdfs-site.xml中进行配置
name | value(默认) | 含义 |
---|---|---|
dfs.namenode.checkpoint.period | 3600 | 3600秒触发一次,数据合并,也就是checkpoint |
dfs.namenode.checkpoint.txns | 1000000 | 100w次操作触发一次 |
dfs.namenode.checkpoint.check.period | 60 | 1分钟执行一次检查操作 |
说明:SNN和NN在一个服务器上,存在单点故障。一旦服务器磁盘损坏,元数据就再也无法找回。实战中,SNN和NN放在不同的服务器上(集群中讲解)。
6.4 HDFS启动流程和安全模式(SafeMode)
安全模式:
HDFS启动过程中, 会进入一个特殊状态(SafeMode),该状态下NameNode暂停接受客户端文件修改操作(只能接收文件读操作)
HDFS启动流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TAtUk2h6-1630554804606)(HDFS笔记.assets/image-20210217113122357.png)]
-
NameNode启动,加载最新的fsimage恢复数据,并加载未合并的editslog_inprogress。一旦在内存中成功建立文件系统元数据的映像,还会创建一个新的fsimage文件和空的editlog(这操作不需要SNN的辅助)。— NN管理内存数据完整。
-
等待接受DataNode的心跳 HeartBeat ,向NameNode上报以下信息(fsimage中不存储数据块的位置,安全模式下由DN向NN发送位置信息)。
DN的本节点地址 健康状态 磁盘容量 剩余容量 版本号
-
等待接受DataNode的块报告 Block Report(保存的全部Block的信息: block的id offset length ),直到满足以下2个条件才退出安全模式
判断数据块是否满足最小副本因子(dfs.namenode.replication.min),默认值1 ,即数据块至少要有1个完整的块。
判断所有满足最小副本因子的块的比例是否达到要求(dfs.namenode.safemode.threshold-pct),默认值99.9%。如果设置大于1,则永远不会退出安全模式 -
满足条件后,不会立刻退出安全模式。
满足条件后,hdfs还会处于安全模式一定时间(dfs.namemode.safemode.extension)。默认值(30000毫秒),这项值可以设置为0。
-
HDFS退出安全模式,才能正常工作。
手动安全模式:
理由:实际开发中为了对HDFS进行维护,会手动NameNode进入安全模式
注意:safemode安全模式下,只能对HDFS中文件进行读操作,不能进行写操作(上传 修改 删除 移动)
0. 查看hfds安全模式状态
hdfs dfsadmin -safemode get
1. 进入安全模式
hdfs dfsadmin -safemode enter
2. 退出安全模式
hdfs dfsadmin -safemode leave
6.5 副本存放机制-机架感知(rack-aware)
数据块副本是为了保证数据的完整性,提高容灾能力。为了更好的提高副本的作用,HDFS有一套副本存放机制。
考虑要素:
- 同1个块的多个副本不能放到同1台DN上,防止被一锅端
- HDFS集群的DN有很多台节点,分布在不同的机架上甚至不同的机房
- 节点内部的网络数据传输, 速度最快. 同1机架次之
机架感知-副本存放策略(hadoop2.7.6以前)–旧版本
- 第一个block副本放在客户端所在的服务器的datanode中。
- 第二个block副本放置在本机架内的其它数据节点datanode上
- 第三个block副本放置在不同机架的随机某个节点上。(防止某个机架数据丢失)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Q8q70Fy-1630554804607)(HDFS笔记.assets/image-20210217115214641.png)]
机架感知-副本存放策略(hadoop2.8.4以后)–新版本
- 第一个block副本,放在client所在的节点
- 第二个block副本,放在另一个机架上的某个节点上。
- 第三个block副本,放在第二个机架的不同节点上。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JDhrkOPg-1630554804608)(HDFS笔记.assets/image-20210217115400758.png)]
7 HDFS完全分布式集群搭建(hadoop1.x)
7.1 集群规划
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q92DbecP-1630554804609)(HDFS笔记.assets/image-20210217123928646.png)]
Hadoop11机器:
启动NameNode和1个DataNode
Hadoop12机器:
启动SecondaryName和1个DataNode
Hadoop13机器:
启动1个DataNode
这样,虽然一共只有3个机器,但是HDFS集群有1个NN、1个SNN和3个DN节点。
7.2 免密登录
HDFS是面向分布式集群环境设计的,整个HDFS集群节点的启动需要跨机器启动,也就需要远程登录到相应的Linux服务器启动HDFS节点。为了简化启动时的认证流程,需要使用免密登录。
start-dfs.sh和stop-dfs.sh的原理:
start-dfs.sh 执行后,会远程登录到NN和DN节点上执行
hadoop-daemon.sh start namenode
启动NN节点,执行hadoop-daemon.sh start datanode
启动DN节点,执行hadoop-daemon.sh start secondarynamenode
启动SNN节点。
stop-dfs.sh也是一样的流程。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3pRBSEY0-1630554804609)(HDFS笔记.assets/image-20210217144015088.png)]
免密登录配置:
-
生成密钥对
ssh-keygen 按3次回车
-
将公钥发送到要免密登录的机器上
ssh-copy-id 其它机器ip或者主机名
7.3 搭建步骤
-
克隆3台安装过Hadoop机器,并进行环境初始化
1.修改ip vi /etc/sysconfig/network-scripts/ifcfg-ens33 修改IPADDR systemctl restart network #重启网络服务 2.配置hostname hostnamectl set-hostname 主机名 # 分别设置 hadoop11 hadoop12 hadoop13 3.域名映射 vi /etc/hosts 192.168.146.11 hadoop11 192.168.146.12 hadoop12 192.168.146.13 hadoop13 4.关闭防火墙 systemctl stop firewalld systemctl disable firewalld
-
配置免密登录
1.在hadoop11机器上生成密钥对 ssh-keygen 按3次回车 2.复制公钥到hadoop11、hadoop12和hadoop13机器上 ssh-copy-id hadoop11 ssh-copy-id hadoop12 ssh-copy-id hadoop13 3.测试一下 ssh hadoop12
-
修改配置文件(hadoop-2.9.2/etc/hadoop)
-
hadoop-env.sh 配置JAVA_HOME
set JAVA_HOME=/opt/installs/jdk1.8.0_291
-
core-site.xml配置NN入口和数据保存的位置
<configuration> <property> <name>fs.defaultFS</name> <value>hdfs://hadoop11:9000</value> </property> <property> <name>hadoop.tmp.dir</name> <value>/opt/installs/hadoop-2.9.2/data</value> </property> </configuration>
-
hdfs-site.xml配置副本数量和SNN节点信息
<configuration> <!-- 副本数量--> <property> <name>dfs.replication</name> <value>3</value> </property> <!-- SNN节点信息--> <property> <name>dfs.namenode.secondary.http-address</name> <value>hadoop12:50090</value> </property> <property> <name>dfs.namenode.secondary.https-address</name> <value>hadoop12:50091</value> </property> </configuration>
-
slaves配置多个DataNode节点
hadoop11 hadoop12 hadoop13
-
将以上配置同步到其它机器上
#同步到hadoop12机器 scp hadoop-env.sh root@hadoop12:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp core-site.xml root@hadoop12:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp hdfs-site.xml root@hadoop12:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp slaves root@hadoop12:/opt/installs/hadoop-2.9.2/etc/hadoop/ #同步到hadoop13机器 scp hadoop-env.sh root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp core-site.xml root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp hdfs-site.xml root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/ scp slaves root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/
-
-
初始化HDFS集群
1.删除每一台机器克隆来的data数据 rm -rf /opt/installs/hadoop-2.9.2/data 2.格式化集群(在namenode节点执行格式化命令) hdfs namenode -format
-
启动HDFS集群
#在拥有免密登录权限的机器上(hadoop11)执行如下命令 start-dfs.sh #分别在hadoop11、hadoop12和hadoop13执行jps查看hdfs进程 [root@hadoop11 hadoop]# jps 5076 NameNode 5206 DataNode 5435 Jps [root@hadoop2 installs]# jps 4628 DataNode 4729 SecondaryNameNode 4795 Jps [root@hadoop13 opt]# jps 1810 Jps 1732 DataNode
-
在windows中通过web界面访问hdfs
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pXj132Mh-1630554804610)(HDFS笔记.assets/image-20210217141749847.png)]
windows最好也进行域名映射,否则只能通过ip访问
/hadoop-2.9.2/etc/hadoop/
#同步到hadoop13机器
scp hadoop-env.sh root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/
scp core-site.xml root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/
scp hdfs-site.xml root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/
scp slaves root@hadoop13:/opt/installs/hadoop-2.9.2/etc/hadoop/
```
-
初始化HDFS集群
1.删除每一台机器克隆来的data数据 rm -rf /opt/installs/hadoop-2.9.2/data 2.格式化集群(在namenode节点执行格式化命令) hdfs namenode -format
-
启动HDFS集群
#在拥有免密登录权限的机器上(hadoop11)执行如下命令 start-dfs.sh #分别在hadoop11、hadoop12和hadoop13执行jps查看hdfs进程 [root@hadoop11 hadoop]# jps 5076 NameNode 5206 DataNode 5435 Jps [root@hadoop2 installs]# jps 4628 DataNode 4729 SecondaryNameNode 4795 Jps [root@hadoop13 opt]# jps 1810 Jps 1732 DataNode
-
在windows中通过web界面访问hdfs
[外链图片转存中…(img-pXj132Mh-1630554804610)]
windows最好也进行域名映射,否则只能通过ip访问
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BeS4W82a-1630554804611)(HDFS笔记.assets/image-20210217142040717.png)]