Hadoop 之 HDFS
1 HDFS 概述
1.1 HDFS 产出背景及定义
随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。
HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。
1.2 HDFS优缺点
优点:
- 高容错性
- 数据自动保存多个副本。它通过增加副本的形式,提高容错性
- 某一个副本丢失以后,它可以自动恢复
- 适合处理大数据
- 可构建在廉价机器上,通过多副本机制,提高可靠性
缺点:
- 不适合低延时数据访问,比如毫秒级的存储数据
- 无法高效的对大量小文件进行存储
- 不支持并发写入、文件随机修改
1.3 HDFS组成架构
1.4 HDFS文件块大小
HDFS 中的文件在物理上是分块存储(Block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x 版本中是 128M,老版本中是 64M。
如果寻址时间为 100ms,即查找目标 Block 的时间是 100ms。
寻址时间与传输时间的比例为 100 : 1为最佳状态,因此传输时间为 1ms。
目前磁盘的传输速率大概在 100MB/s,取个整大概就是 128MB。
2 HDFS 的 Shell 操作
(1)-help:输出这个命令参数
(2)-ls:显示目录信息
(3)-mkdir:在 HDFS 上创建目录
(4)-moveFromLocal:从本地剪切粘贴到 HDFS
(5)-appendToFile:追加一个文件到已经存在的文件末尾
(6)-cat:显示文件内容
(7)-chgrp 、-chmod、-chown:Linux 文件系统中的用法一样,修改文件所属权限
(8)-copyFromLocal:从本地文件系统中拷贝文件到 HDFS 路径去
(9)-copyToLocal:从 HDFS 拷贝到本地
(10)-cp :从 HDFS 的一个路径拷贝到 HDFS 的另一个路径
(11)-mv:在 HDFS 目录中移动文件
(12)-get:等同于 copyToLocal,就是从 HDFS 下载文件到本地
(13)-getmerge:合并下载多个文件,比如 HDFS 的目录 /user/djm/test 下有多个文件:log.1, log.2,log.3,...
(14)-put:等同于 copyFromLocal
(15)-tail:显示一个文件的末尾
(16)-rm:删除文件或文件夹
(17)-rmdir:删除空目录
(18)-du:统计文件夹的大小信息
(19)-setrep:设置 HDFS 中文件的副本数量
3 HDFS 客户端操作
package com.djm.hdfsclient;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import org.junit.After;import org.junit.Before;import org.junit.Test;import java.io.IOException;import java.net.URI;public class HdfsClient { FileSystem fileSystem = null; @Before public void init() { try { fileSystem = FileSystem.get(URI.create("hdfs://hadoop102:9000"), new Configuration(), "djm"); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * 上传文件 */ @Test public void put() { try { fileSystem.copyFromLocalFile(new Path("C:\\Users\\Administrator\\Desktop\\Hadoop 入门.md"), new Path("/")); } catch (IOException e) { e.printStackTrace(); } } /** * 下载文件 */ @Test public void download() { try { // useRawLocalFileSystem表示是否开启文件校验 fileSystem.copyToLocalFile(false, new Path("/Hadoop 入门.md"), new Path("C:\\Users\\Administrator\\Desktop\\Hadoop 入门1.md"), true); } catch (IOException e) { e.printStackTrace(); } } /** * 删除文件 */ @Test public void delete() { try { // recursive表示是否递归删除 fileSystem.delete(new Path("/Hadoop 入门.md"), true); } catch (IOException e) { e.printStackTrace(); } } /** * 文件重命名 */ @Test public void rename() { try { fileSystem.rename(new Path("/tmp"), new Path("/temp")); } catch (IOException e) { e.printStackTrace(); } } /** * 查看文件信息 */ @Test public void ls() { try { RemoteIterator listFiles = fileSystem.listFiles(new Path("/etc"), true); while (listFiles.hasNext()) { LocatedFileStatus fileStatus = listFiles.next(); if (fileStatus.isFile()) { // 仅输出文件信息 System.out.print(fileStatus.getPath().getName() + " " + fileStatus.getLen() + " " + fileStatus.getPermission() + " " + fileStatus.getGroup() + " "); // 获取文件块信息 BlockLocation[] blockLocations = fileStatus.getBlockLocations(); for (BlockLocation blockLocation : blockLocations) { // 获取节点信息 String[] hosts = blockLocation.getHosts(); for (String host : hosts) { System.out.print(host + " "); } } System.out.println(); } } } catch (IOException e) { e.printStackTrace(); } } @After public void exit() { try { fileSystem.close(); } catch (IOException e) { e.printStackTrace(); } }}
4 HDFS 的数据流
4.1 HDFS写数据流程
4.1.1 剖析文件写入
1、客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
2、NameNode 返回是否可以上传。
3、客户端请求第一个 Block 上传到哪几个 DataNode。
4、NameNode 返回三个节点,分别是 dn1、dn2、dn3。
5、客户端通过 FSDataOutputStream 模块请求 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
6、按倒序逐级响应客户端。
7、客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位,dn1 收到一个Packet 就会传给 dn2,dn2 传给 dn3;dn1 每传一个 packet 会放入一个应答队列等待应答。
8、当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。
4.1.2 网络拓扑-节点距离计算
在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。那么这个最近距离怎么计算呢?
4.1.3 机架感知
4.2 HDFS读数据流程
1、客户端通过 Distributed FileSystem 向 NameNode 请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。
2、根据就近原则挑选一台 DataNode,请求读取数据。
3、DataNode 开始传输数据给客户端。
4、客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。
5 NameNode 和 SecondaryNameNode
5.1 NN 和 2NN 工作机制
如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低,因此,元数据必须存放在内存中,周所周知,内存的特点是速度快,断电后丢失数据,一旦断电,元数据丢失,整个集群就无法工作了,因此产生了用于备份元数据的 FsImage。
但是这样又会引发一个问题,当内存中的元数据更新时,FsImage 是否要同时更新,如果要同步更新,就会导致效率低,如果不同步更新,就会导致数据一致性问题,一旦突然断电,就会丢失一部分数据,因此,引入了 Edits(只进行追加操作,效率很高),每当元数据进行增加或者修改时,先追加到 Edits,在修改内存,这样的话,一旦断电,可以通过 FsImage 和 Edits 合成元数据。
但是,如果长时间添加数据到 Edits,导致 Edits 过大,还是会影响效率,而且一旦断电,恢复元数据的时间也会相应增加,因此,需要定期的对 FsImage 和 Edits 进行合并,如果这个操作由 NameNode 去完成,又会效率低(因为在合并后不能处理写请求),所以引入了 SecondaryNameNode,专门用来做合并操作。
NameNode 工作:
1、第一次启动 NameNode格式化后,创建 Fsimage 和 Edits 文件,如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
2、客户端对元数据进行增删改操作。
3、NameNode 记录操作日志,更新滚动日志。
4、NameNode 在内存中对元数据进行增删改操作。
Secondary NameNode 工作:
1、Secondary NameNode 询问 NameNode 是否需要 CheckPoint,直接带回 NameNode 是否检查结果。
2、Secondary NameNode请求执行CheckPoint。
3、NameNode 滚动正在写的 Edits 日志。
4、将滚动前的编辑日志和镜像文件拷贝到 Secondary NameNode。
5、Secondary NameNode 加载编辑日志和镜像文件到内存合并。
6、生成新的镜像文件 fsimage.chkpoint。
7、拷贝 fsimage.chkpoint 到 NameNode。
8、NameNode 将 fsimage.chkpoint 重命名为 fsimage。
5.2 Fsimage 和 Edits 解析
oiv 查看Fsimage 文件
- hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
oev 查看 Edits 文件
- hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径
5.3 CheckPoint 时间设置
满足以下两个条件都会触发合并操作:
通常情况下,SecondaryNameNode 每隔一小时执行一次。
[hdfs-default.xml]
dfs.namenode.checkpoint.period 3600
一分钟检查一次操作次数,当次数到达 100 万次就会触发操作。
[hdfs-default.xml]
dfs.namenode.checkpoint.txns 1000000 操作动作次数 dfs.namenode.checkpoint.check.period 60 1分钟检查一次操作次数
5.4 NameNode 故障处理
NameNode 故障后,可以采用如下两种方法恢复数据:
将 2NN 中的数据拷贝到 NN 存储数据的目录。
使用 -importCheckpoint 选项启动 NN 守护进程,从而将 2NN 中数据拷贝到 NN 目录中。
- hdfs namenode -importCheckpoint
5.5 集群安全模式
基本命令:
hdfs dfsadmin -safemode get:查看安全模式状态
hdfs dfsadmin -safemode enter:进入安全模式状态
hdfs dfsadmin -safemode leave:离开安全模式状态
hdfs dfsadmin -safemode wait:等待安全模式状态
6 DataNode
6.1 DataNode工作机制
1、一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
2、DataNode 启动后向 NameNode 注册,通过后,周期性(1小时)的向 NameNode 上报所有的块信息。
3、心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令如复制块数据到另一台机器,或删除某个数据块,如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用。
4、集群运行中可以安全加入和退出一些机器。
6.2 数据完整性
1、当 DataNode 读取 Block 的时候,它会计算 CheckSum。
2、如果计算后的 CheckSum,与 Block 创建时值不一样,说明 Block 已经损坏。
3、Client 读取其他 DataNode 上的 Block。
4、在其文件创建后周期验证。
6.3 掉线时限参数设置
[hdfs-site.xml]
dfs.namenode.heartbeat.recheck-interval 300000 毫秒 dfs.heartbeat.interval 3 秒
6.4 服役新数据节点
将 hadoop102 上的 java、hadoop、profile 发送到新主机,source 一下 profile,直接启动即可加入集群。
6.5 退役旧数据节点
6.5.1 黑名单设置
创建黑名单
[djm@hadoop101 hadoop]$ touch blacklist
配置加入黑名单的主机
hadoop102
配置 hdfs-site.xml
dfs.hosts.exclude /opt/module/hadoop-2.7.2/etc/hadoop/blacklist
刷新 namenodes
[djm@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes
更新 ResourceManager 节点
[djm@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes
如果数据不均衡,可以用命令实现集群的再平衡
[djm@hadoop102 hadoop-2.7.2]$ start-balancer.sh
6.5.2 白名单设置
创建白名单
[djm@hadoop101 hadoop]$ touch whitelist
配置加入黑名单的主机
hadoop102hadoop103hadoop104
配置 hdfs-site.xml
dfs.hosts /opt/module/hadoop-2.7.2/etc/hadoop/whitelist
刷新 namenodes
[djm@hadoop102 hadoop-2.7.2]$ hdfs dfsadmin -refreshNodes
更新 ResourceManager 节点
[djm@hadoop102 hadoop-2.7.2]$ yarn rmadmin -refreshNodes
如果数据不均衡,可以用命令实现集群的再平衡
[djm@hadoop102 hadoop-2.7.2]$ start-balancer.sh
黑白名单的区别:
白名单比较严格,黑名单比较平缓,处于黑名单中的主机会同步数据结束后继续处于集群,只是不在处理请求而已,而不处于白名单中的主机会直接被干掉。
6.6 Datanode多目录配置
DataNode也可以配置成多个目录,每个目录存储的数据不一样,即:数据不是副本。
hdfs-site.xml
dfs.datanode.data.dir file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2
7 HDFS 2.X新特性
7.1 集群间数据拷贝
采用 distcp 命令实现两个 Hadoop 集群之间的递归数据复制
[djm@hadoop102 hadoop-2.7.2]$ hadoop distcp hdfs://haoop102:9000/user/djm/hello.txt hdfs://hadoop103:9000/user/djm/hello.txt
7.2 小文件存档
归档文件
[djm@hadoop102 hadoop-2.7.2]$ hadoop archive -archiveName input.har -p /user/djm/input /user/djm/output
查看归档
[djm@hadoop102 hadoop-2.7.2]$ hadoop fs -lsr har:///user/djm/output/input.har
解归档文件
[atguigu@djm hadoop-2.7.2]$ hadoop fs -cp har:/// user/djm/output/input.har/* /user/djm