Hadoop之HDFS实用篇

系列文章目录

Hadoop了解篇
Hadoop之HDFS
Hadoop之MapReduce
Hadoop之Yarn
Hadoop之优化&新特性


文章目录

  • 系列文章目录
  • 前言
  • 一、HDFS是什么?
    • 1.HDFS
    • 2.应用场景
    • 3.HDFS特点
  • 二、HDFS组成
    • 1.构架
    • 2.HDFS文件块(Block)大小的如何确定?
    • ***why?***
    • 3.HDFS的Shell操作
  • 二、HDFS客户端操作
    • 1.HDFS客户端环境准备
    • 2.HDFS的API操作
  • 二、HDFS读写数据流程
    • 1.HDFS写数据流程
    • 1.1 客户端数据先发送给哪个DataNode呢?是随机的吗?
    • 1.2 副本储存的节点是如何选择的呢?
    • 1.3 建立传输通道时,某一传输通道连接不上,怎么办?
    • 1.4 写数据时,某一传输通道连接不上,怎么办?
    • 2.HDFS读数据流程
    • 2.1 步骤4传输中断怎么办?
    • 2.2 blk_1、blk_2可以同时读吗?
  • 三、NameNode和SecondaryNameNode
    • 1.NameNode中的数据存储在哪里呢?
    • 2.Fsimage和Edits进步解析?
    • 3.Fsimage中为什么没有记录DataNode?
    • 4.CheckPoint时间设置
    • 5.Secondary NameNode中的元数据完整吗?
    • 6.集群安全模式
  • 四、DataNode
    • 1.工作机制
    • 2.DataNode上数据损坏,怎么办?
    • 3.退役节点
  • 总结


前言

当下数据量的爆发式增长,在一个操作系统中,我们很难存下所有数据,这时就需要将数据放在等多个操作系统的磁盘中。此时另一个难题就出来了,我们如何对多台电脑的磁盘进行管理呢?这个时候分布式文件管理系统就登场了。


一、HDFS是什么?

1.HDFS

是一个文件系统,用于储存文件,通过目录树来定位文件
并且是分布式的,文件分布在多台服务器的磁盘中。

2.应用场景

适合一次写入,多次读出,不支持文件的修改。(内部维持多个副本,随机写的话,分布式数据一致性会受到挑战。而如果一定要保证实时的数据一致性,那么性能上的牺牲就会太大了。所以说,随机写不属于HDFS的适用场景。)

3.HDFS特点

优点:

特点 为何?
高容错性 内部维持多个副本,单一副本丢失,可自动恢复
处理数据量大 最大处理TB、PB级别的数据;处理百万规模的文件数量
可在廉价机器上 内部维持多个副本,单一副本丢失,可自动恢复

缺点:

特点 为何?
低延迟储存做不到 多副本机制的弊端 ,毫秒级储存难以达到
多小文件高效存储做不到 会占用大量的NameNode的内存来储存文件元数据;小文件的寻址时间会超过读取时间
并发写入,随机修改做不到 一个文件只能一个写,不可以多线程同时写;仅支持数据的追加(Append)

二、HDFS组成

1.构架

组件 作用
NameNode 管理元数据、配置副本策略、管理Block映射信息、处理客户端读写请求
DataNode 存储实际的数据块、执行数据的读/写操作
Client 文件切分成Block然后上传 、与NameNode交互,获取文件位置信息、与DataNode交互,读取/写入数据、提供命令管理/操作HDFS,eg:对NameNode的格式化
Secondory NameNode 紧急情况下,可辅助恢复NameNode了,具体见后续

2.HDFS文件块(Block)大小的如何确定?

首先明白:HDFS上的文件在物理上是分块存储(Block),块的大小我们可以根据实际的生产环境通过配置参数(dfs blocksize)来设定。在老版本中默认大小为64M,新版本(2.X)中默认大小为128M。

why?

以从HDFS上下载一个文件为例:

约定:寻址时间为传输时间的1%时,为最佳状态
1.假设寻址时间为10ms,即查找目标Block的时间为10ms
2.因此在最佳状态下,传输时间为10/0.01=1s
3.而目前磁盘的传输速率普遍为100M/S
4.1S * 100M/S = 100M
5.最接近100M就是128M

3.HDFS的Shell操作

1)基本语法

bin/hadoop fs 具体命令
or
bin/hdfs dfs 具体命令

2)常用命令实操
(1)上传

-moveFromLocal:从本地剪切粘贴到HDFS上
hadoop fs -moveFromLocal ./helloworld.txt /input

-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
hadoop fs -copyFromLocal ./helloworld.txt /input

-appendToFile:追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile helloworld.txt /input/yilei.txt

-put:等同于copyFromLocal
hadoop fs -put ./helloworld.txt /input

(2)下载

-copyToLocal:从HDFS上拷贝到本地
hadoop fs -copyToLocal /input/helloworld.txt ./

-get:等同于copyToLocal
hadoop fs -get ./helloworld.txt /input

-getmerge:合并多个文件下载
hadoop fs -getmerge /user/yilei/bin/* ./helloworld.txt

3)HDFS直接操作

-ls:显示目录信息
hadoop fs -ls

-mkdir:在HDFS上创建目录
hadoop fs -mkdir /sanguo/liubei.txt

-cat:显示文件内容
hadoop fs -cat /sanguo/liubei.txt

-cp :从HDFS的一个路径拷贝到HDFS的另一个路径
hadoop fs -cp /sanguo/liubei.txt /input/

-du:统计文件夹的大小信息
hadoop fs -du -s -h /sanguo
2.7k  /sanguo

-setrep:设置HDFS中的文件副本数
hadoop fs -setrep 10 /sanguo/liubei.txt

二、HDFS客户端操作

1.HDFS客户端环境准备

1)下载Hadoop
2)配置Hadoop的环境变量
3)配置Path环境变量,重启电脑
4)创建Maven工程,并导入相应的依赖

2.HDFS的API操作

获取文件系统对象的方式一:(常用方式)

public class HdfsClient{
	@Test
	public void testMkdirs(){
	//连接地址
	UIR uri = new URI("hdfs://hadoop01:9820");
	//创建配置文件对象
	Configuration conf = new Configuration();
	//1.文件系统对象
	/*
	参数一:NameNode的连接地址
	参数二:配置文件对象
	参数三:操作hdfs的用户
	*/
	FileSystem fs = FileSystem.get(uri,conf,"yilei")
	//2.对应操作
	System.out.println(fs);
	//3.关闭资源
	fs.close();
	}
}

获取文件系统对象的方式二:
注:需要在EditConfigurations中配置
VM options: -DHADOOP_USER_NAME=yilei

public class HdfsClient{
	@Test
	public void testMkdirs(){
	//创建配置文件的对象
	Configuration conf = new Configuration();
	//通过配置文件配置NameNode的地址
	conf.set("fs.defaultFS","hdfs://hadoop01:9820");
	FileSystem fs = FileSystem.get(conf);
	//2.对应操作
	System.out.println(fs);
	//3.关闭资源
	fs.close();
	}
}

客户端操作上传文件

@Test
public void test() throws IOException(){
	/*
	参数一:是否删除源文件
	参数二:是否覆盖目标文件(目标文件已经存在的情况下)
		true:覆盖
		false:不覆盖,但是目标文件存在的情况下会抛异常
	参数三:源文件路径
	参数四:目标文件路径
	*/
	fs.copyFromLocalFile(true,true,new Path("D:\\tset\\aa.txt"),new Path("/"))
}

客户端操作下载文件

@Test
public void test1() throws IOException(){
	/*
	参数一:是否删除源文件
	参数二:源文件路径
	参数三:目标文件路径
	参数四:是否使用RawLocalFileSystem
		false:会生成crc文件
		true:不会生成crc文件
	*/
	fs.copyToLocalFile(false,new Path("/aa.txt"),new Path("D://test"),true);
}

文件删除

@Test
public void test1() throws IOException(){
	/*
	参数一:要删除的文件或目录的路径
	参数二:只对目录有效,如果是一个目录那么必须为true,如果文件就无所谓
	*/
	fs.delete(new Path("/cc.txt"),true);
}

文件名更改

@Test
public void test1() throws IOException(){
	/*
	 第一个参数 :源文件路径(文件修改名字前的路径)
     第二个参数 :目标文件路径 (文件修改名字后的路径)
	*/
	fs.delete(new Path("/cc.txt"),new Path("aa.txt"));
}

查看文件详情

@Test
public void test1() throws IOException(){
	/*
	 第一个参数 : 要遍历的目录路径
     第二个参数 : 是否递归(是否查看子目录中的内容)
	*/
    RemoteIterator<LocatedFileStatus> fileStatus = fs.listFiles(new Path("/"), true);
        //是否有下一个元素
        while(fileStatus.hasNext()){
            System.out.println("===================文件信息=================");
            //获取一个元素
            LocatedFileStatus file = fileStatus.next();
            //获取文件的名称
            System.out.println("文件名:" + file.getPath().getName());
            System.out.println("副本数:" + file.getReplication());
            System.out.println("-----------------块信息---------------------");
            BlockLocation[] blockLocations = file.getBlockLocations();
            System.out.println(Arrays.toString(blockLocations));
        }
}

判断是文件还是目录

@Test
public void test2() throws IOException {
    FileStatus[] status = fs.listStatus(new Path("/"));
	for (FileStatus file : status) {
        if (file.isFile()){
            System.out.println(file.getPath().getName() + "是一个文件");
        }else if (file.isDirectory()){
            System.out.println(file.getPath().getName() + "是一个目录");
        }
    }
}

通过流向HDFS上传或下载文件
上传(fs为文件系统对象)

@test
public void test3()throws IOException{
	//1.读 - 本地
	FileInputStream fis = new FileInputStream("D:\\test\\aa.txt");
	//2.写 - HDFS
	FSDataOutputStream os = fs.create(new Path("/aa.txt"));
	//3.一边读一遍写(文件对拷)
	//参数三:缓冲区大小
	//参数四:对拷完毕是否关流
	IOUtils.copyBytes(fis,os,3000,true);
}

下载(fs为文件系统对象)

@test
public void test4()throws IOException{
	//1.读 - HDFS
	FSDataInputStream fis = fs.open(new Path("/aa.txt"));
	//2.写 - 本地
	FileOutputStream fos = new FileOutputStream(new Path("d:\\test\\aa.txt"));
	//3.一边读一遍写(文件对拷)
	//参数三:缓冲区大小
	//参数四:对拷完毕是否关流
	IOUtils.copyBytes(fis,fos,3000,true);
}

二、HDFS读写数据流程

1.HDFS写数据流程

Hadoop之HDFS实用篇_第1张图片

步骤详述
1、客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode请求上传文件,NameNode检查文件是否已存在,父目录是否存在
2、NameNode返回是否上传
3、客户端请求第一个Block上传到哪几个DataNode服务器上
4、NameNode返回3个DataNode节点,分别为n1、n2、n3
5、客户端通过FSDataOutputStream模块请求n1上传数据,n1收到请求会继续调用n2,然后n2调用n3,将这个通信管道建立完成
6、n1、n2、n3逐级应答客户端
7、客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位(一个Packet为64K),dn1收到一个Packet就会传给dn2(同时会往本地磁盘写),dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答
8、当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器(重复执行3-7步)

1.1 客户端数据先发送给哪个DataNode呢?是随机的吗?

答:不是随机,客户端会选择距离待上传数据最近的DataNode接收数据。

那如何知道它的距离是最近呢?

Hadoop之HDFS实用篇_第2张图片
两节点的距离=两节点到达最近的共同祖先的距离总和

eg:Distance(/d1/r1/n0,/d1/r1/n0)=0 (统一节点上的进程)
Distance(/d1/r2/n1,/d2/r4/n1)=6 (不同数据中心的节点)

1.2 副本储存的节点是如何选择的呢?

副本节点选择(Hadoop3.X)
第一个副本:在client所处节点上,若客户端在集群外,随机选一个
第二个副本:在另外一个机架的随机一个节点上
第三个副本:在第二个副本所在机架的随机节点(不与第二副本所在节点相同)

1.3 建立传输通道时,某一传输通道连接不上,怎么办?

答:重新建立传输通道,此时就会跳过刚才连接失败的节点;
此时可能就会存在疑问,该案例中是不是就会少了一个副本,短期看是的;
DataNode会定期向NameNode汇报块信息,此时NameNode一旦发现异常,会进行对应的修复,保证Datanode与NameNode的一致性。

1.4 写数据时,某一传输通道连接不上,怎么办?

答:会进行四次尝试,如果还是连接不上则跳过该节点,向其他节点传输

2.HDFS读数据流程

Hadoop之HDFS实用篇_第3张图片

步骤详述
1、客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件所在的DataNode地址
2、挑选一台DataNode(就近原则,然后随机)服务器,请求下载数据
3、DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)
4、客户端以Packet为单位接收,先在本地缓存,然后写入目标文件

2.1 步骤4传输中断怎么办?

答:客户端会将读取到的不完整的数据进行清除,重新找一个节点下载blk_1;不存在断点下载。

2.2 blk_1、blk_2可以同时读吗?

答:可以,前提是两个客户端(可以并发读,不支持并发写),但是两个客户端读的是两份hello.txt。

三、NameNode和SecondaryNameNode

1.NameNode中的数据存储在哪里呢?

假设在磁盘中,我们随机访问时效率会很低
假设在内存中,数据就很容易就丢失了
上面两个假设都不成立,除非上述两种情况同时并行,磁盘内存都存一份
Hadoop之HDFS实用篇_第4张图片

第一阶段: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 checkpoint
7、拷贝fsimage checkpoint到NameNode
8、NameNode将fsimage checkpoint重新命名成fsimage

2.Fsimage和Edits进步解析?

NameNode被格式化之后,将在/opt/module/hadoop/data/tmp/dfs/name/current目录中产生如下文件

  • fsimage_000000000000000000
  • fsimage_000000000000000000.md5
  • seen_txid
  • version

Fsimage文件:HDFS文件系统元数据的一个永久性检查点,里面包含HDFS文件系统的所有目录和文件inode的序列化信息;

Edits文件:存放文件系统所有的写操作,客户端执行的写操作首次会被记录到Edits文件中;

seen_txid文件:保存最后一个edits_的数字;
:每次NameNode启动的时候都会将fsimage文件读到内存,加载Edits里面的更新操作,保证内存中的元数据信息都是最新的。

3.Fsimage中为什么没有记录DataNode?

通过查看fsimage_000000000000000000文件,我们并不能看到关于记录块对应的DataNode的信息,为什么?

  • 答:集群启动后,要求DataNode上报数据块信息,并隔一段时间再次上报。

4.CheckPoint时间设置

1)通常情况下,SecondaryNameNode每隔一小时执行一次。

hdfs-default.xml

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600</value>
</property>

2)自定义

<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 >

5.Secondary NameNode中的元数据完整吗?

答:当NameNode故障,通过Secondary NameNode恢复的元数据是不完整的,最新编辑日志的元数据丢失,这些数据还没有Checkpoint。

6.集群安全模式

1)集群处于安全模式,不能执行重要操作(写操作)。集群启动完成后,自动退出安全模式。

查看当前模式

hdfs dfsadmin -safemode get
Safe mode is OFF

bin/hdfs dfsadmin -safemode get		(功能描述:查看安全模式状态)
bin/hdfs dfsadmin -safemode enter  	(功能描述:进入安全模式状态)
bin/hdfs dfsadmin -safemode leave	(功能描述:离开安全模式状态)
bin/hdfs dfsadmin -safemode wait	(功能描述:等待安全模式状态)

四、DataNode

1.工作机制

Hadoop之HDFS实用篇_第5张图片

步骤详述
1、一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
2、DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息。
3、心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个DataNode的心跳,则认为该节点不可用。
4、集群运行中可以安全加入和退出一些机器。

2.DataNode上数据损坏,怎么办?

DataNode节点保证数据完整性的方法:

  • DataNode读取Block的时候,会计算CheckSum
  • 若计算的CheckSum,与Block创建时值不一样,说明Block已经损坏
  • Client读取其他DataNode上的Block
  • DataNode在其文件创建后周期性验证CheckSum

3.退役节点

添加白名单:添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。
1)在NameNode的/opt/module/hadoop-3.1.3/etc/hadoop目录下创建dfs.hosts文件

hadoop01
hadoop02
hadoop03

2)在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性

<property>
<name>dfs.hosts</name>
<value>/opt/module/hadoop-3.1.3/etc/hadoop/dfs.hosts</value>
</property>

3)配置文件分发
4)刷新NameNode

hdfs dfsadmin -refreshNodes

5)更新ResourceManager节点

yarn rmadmin -refreshNodes

6)如果数据不均衡,可以用命令实现集群的再平衡

[yilei@hadoop02 sbin]$ ./start-balancer.sh

总结

关于HDFS的内容就总结到这里,欢迎小伙伴们给与指正,同时如果对你有帮助,也劳驾动起你的小手手,投币三联哦!!!

你可能感兴趣的:(hadoop,hdfs)