02 HDFS

1 HDFS 概述

1.1 HDFS产出背景及定义

产出背景

● 随着数据量变大,系统存不下,分配更多系统磁盘,但是管理不方便。

● 需要一种系统来管理多态机器上的文件,这就是分布式文件管理系统。

● HDFS — 分布式文件管理系统

定义:

● HDFS(Hadoop Distributed File System):文件系统、分布式的

● HDFS的使用场景:一次写入,多次读出,不能修改

● 适合用来做数据分析,不适合用来做网盘应用。

1.2 HDFS优缺点

优点:

高容错性

● 适合处理大数据

● 可构建在廉价机器

缺点:

● 不适合低延时数据访问

● 无法高效 的对大量小文件进行存储

● 不支持并发写入、文件随机修改

(1) 一个文件只能有一个写,不允许多个线程同时写

(2) 仅支持数据append(追加),不支持文件的随机修改。

1.3 HDFS组成架构

构架图:

1)NameNode(nm):就是Master,它是一个主管、管理者

2)DataNode(dn):就是Slave,NameNode下达命令,DataNode执行实际的操作

3)Client:客户端

4)Secondary NameNode:并非NameNode热备,当NameNode挂掉时,它并不能马上替换NameNode并提供鼓舞。

1.4 HDFS文件块大小(面试重点)

● HDFS中的文件在物理上是分块存储(Block),快的大小通过配置参数(dfs.blocksize)来规定

● 默认大小:Hadoop2.x 为128M,老版本为64M。

思考:为什么块的大小不能设置太小,也不能设置太大?

太小 — 会增加寻址时间,程序一直在找块的开始位置

太大 — 从磁盘传输数据的时间会明显大于定位这个块开始位置的所需时间。导致程序在处理这块数据时,会非常慢。

总结:HDFS块的大小设置主要取决于磁盘传输速度

 

2 HDFS的Shell操作(开发重点)

2.1 基本语法

hadoop fs 具体命令     <=>     hdfs dfs 具体命令

2.2 常用命令

2.2.1 准备工作

1) 启动集群

# start-dfs.sh

# start-yarn.sh

2) -help :输出命令参数

# Hadoop fs -help rm

2.2.2 上传

指令 说明 实例
-moveFromLocal 本地剪切到HDFS hadoop fs -moveFromLocal [本地] [HDFS]
-copyFromLocal 本地拷贝到HDFS hadoop fs -copyFromLocal [本地] [HDFS]
-appendToFile 追加文件 hadoop fs -appendToFile [本地] [HDFS]
-put 等同于copyFromLocal hadoop fs -put [本地] [HDFS]

2.2.3 下载

指令 说明 实例
-copyToLocal HDFS拷贝到本地 hadoop fs -copyToLocal [HDFS] [本地]
-get 等同于 copyToLocal hadoop fs -get [HDFS] [本地]
d-getmerge 合并下载多个文件 hadoop fs -getmerge [HDFS] [本地] 

2.2.4 HDFS直接操作

指令 说明 实例
-ls 在HDFS上创建目录 hadoop fs -ls /
-mkdir 显示目录信息 hadoop fs -mkdir -p /input
-cat 显示文件内容 hadoop fs -cat /input/a.txt
-chgrp -chmod -chown 修改文件所属权限 hadoop fs  -chmod  666   /input/a.txt
-cp HDFS中文件拷贝 haddoop fs -cp  /input/a.txt  /input2
-mv 在HDFS目录中移动文件 hadoop fs -mv  /input2/a.txt  /input
-tail 显示文件的末尾 hadoop fs -tail  /input/a.txt
-rm 删除文件或文件夹 hadoop fs -rm  /input2/a.txt
-rmdir 删除空目录 hadoop fs -mkdir /input3
-du 统计文件夹的大小信息 hadoop fs -du -s -h /input/a.txt
-setrep 设置HDFS中文件的副本数量 hadoop fs -setrep 10 /input/a.txt

 

3 HDFS客户端操作(开发重点)

3.1 客户端环境准备

1) 资料目录下的Windows依赖目录,打开

2) 配置HADOOP_HOME环境变量。

3) 配置Path环境变量。然后重启电脑(如果上述操作后还有问题可以将bin目录下hadoop.dll和winutils.exe放到 C:/windows/system32目录下)

4) 创建一个Maven工程HdfsClientDemo,并导入相应的依赖坐标+日志添加

5) 在项目的src/main/resources目录下,新建一个文件,命名为“log4j2.xml”,在文件中填入

6) 创建包名:com.atguigu.hdfs

7) 创建HdfsClient类

8) 运行时需要配置用户名称

补充:

【案例】注解@Before和@After

public class HDFSDemo {

    @Before
    public void before(){
        System.out.println("1.brefor");
    }

    @After
    public void after(){
        System.out.println("3.after");
    }
    
    @Test
    public void test(){
        System.out.println("2.test");
    }


}

运行结果:

1.brefor
2.test
3.after

【案例2】模板准备

1.通过代码操作HDFS

2.具体操作(上传、下载、删除...)

3.关闭资源

public class HDFSDemo {
    private FileSystem fs;

    @Before
    public void before() throws Exception {
        //1.创建客户端对象
        /*
            get(final URI uri, final Configuration conf, final String user)
            uri:NameNode的地址(通信地址,不是web端地址)
            conf:配置参数的对象
            user:操作HDFS的用户名
         */
        URI uri = new URI("hdfs://hadoop102:8082");
        Configuration conf = new Configuration();    //虽然不用,但是要FileSystem,所以还是要new一个出来
        fs = FileSystem.get(uri,conf,"atguigu");
    }

    @After
    public void after(){
        //3.关闭资源
        try {
            if (fs != null) {
                fs.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //2.具体操作(上传、下载、删除...)
    @Test
    public void test(){

    }

}

3.2 HDFS的API操作

3.2.1 HDFS文件上传

函数介绍

copyFromLocalFile(boolean delSrc, boolean overwrite, Path src, Path dst)
delSrc 是否删除源文件(本地)
overwrite 如果目标文件存在是否覆盖   [true-覆盖  false-不覆盖,如果目标文件存在则报错]
src 源文件路径(本地)
dst 目标文件路径(HDFS)

【案例】上传( 本地->HDFS )

@Test
public void test() throws IOException {

    fs.copyFromLocalFile(true, true, new Path("D:\\OT\\yezi.txt"), new Path("/"));

}

3.2.2 HDFS文件下载

函数介绍

copyToLocalFile(boolean delSrc, Path src, Path dst, boolean useRawLocalFileSystem)
delSrc 是否删除源文件(HDFS)
src 源文件路径(HDFS)
dst 目标文件路径(本地)
useRawLocalFileSystem 是否使用RawLocalFileSystem文件系统
true —— 本地不会生成crc校验和文件
false —— 本地会生成校验和文件

【案例】下载 ( HDFS -> 本地)

@Test
public void test2() throws IOException {

    fs.copyToLocalFile(false, new Path("/yezi.txt"), new Path("D:\\OT"), false);

}

3.2.3 HDFS文件夹删除

函数介绍

delete(Path f, boolean recursive)
f 路径
recursive 是否递归
  文件— true和false都可以
  目录 — ture       空目录 — false也可以

【案例】删除

@Test
public void test3() throws IOException {

    fs.delete(new Path("/abc"),false);

}

3.2.4 HDFS文件夹更改

函数介绍

rename(Path src, Path dst)
src 源文件路径
dst 目标文件路径

【案例1】更名

@Test
public void test4() throws IOException {

    fs.rename(new Path("/input/a.txt"),new Path("/input/b.txt"));

}

【案例2】移动

@Test
public void test4() throws IOException {

    fs.rename(new Path("/input/b.txt"),new Path("/input2"));

}

3.2.5 HDFS文件详情查看

● 函数介

listFiles(final Path f, final boolean recursive)
f 路径
recursive 是否递归

类介绍

说明
RemoteIterator 迭代器--用来迭代所有的文件
LocatedFileStatus 该类中封装了文件所有的详情
BlockLocation 该类中封装了块的详情

【案例】

@Test
public void test5() throws IOException {

    RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);

    while(listFiles.hasNext()){
        //LocatedFileStatus : 该类中封装了文件所有的详情
        LocatedFileStatus fileStatus = listFiles.next();
        System.out.println("文件的名字:" + fileStatus.getPath().getName());
        System.out.println("文件的副本数:" + fileStatus.getReplication());
        System.out.println("文件的大小:" + fileStatus.getLen());

        //获取块的信息
        //BlockLocation :该类中封装了块的详情
        BlockLocation[] blockLocations = fileStatus.getBlockLocations();
        System.out.println(Arrays.toString(blockLocations));
    }
}

运行结果:

文件的名字:b.txt
文件的副本数:3
文件的大小:56
[0,56,hadoop102,hadoop103,hadoop104]

文件的名字:job_1639697652307_0001-1639698054115-atguigu-MRDemo2%2D1.0%2DSNAPSHOT.jar-1639698066271-1-1-SUCCEEDED-default-1639698058806.jhist
文件的副本数:3
文件的大小:22208
[0,22208,hadoop102,hadoop103,hadoop104]

文件的名字:job_1639697652307_0001_conf.xml
文件的副本数:3
文件的大小:215082
[0,215082,hadoop102,hadoop103,hadoop104]

3.2.6 HDFS文件和目录判断

● FileStatus : 在该类中封装了文件或目录的详情

【案例】

@Test
public void test6() throws IOException {
    /*
        FileStatus : 在该类中封装了文件或目录的详情
     */
    FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
    //遍历
    for (FileStatus fileStatus : fileStatuses) {
        if (fileStatus.isFile()){//判断是否是文件
            System.out.println(fileStatus.getPath().getName() + "是一个文件");
        }else if(fileStatus.isDirectory()){//判断是否是目录
            System.out.println(fileStatus.getPath().getName() + "是一个目录");
        }
    }
}

运行结果:

input是一个目录
input2是一个目录
tmp是一个目录
yezi.txt是一个文件

3.2.7 通过流实现文件的上传

● 函数介绍

copyBytes(InputStream in, OutputStream out,int buffSize, boolean close)
in 输入流
out 输出流
buffSize 缓冲区大小  byte[] b = new byte[buffSize];
close 是否关闭资源

【案例】

@Test
public void test7() throws IOException {
    //读
    FileInputStream fis = new FileInputStream("D:\\io\\hdfs\\longge.txt");
    //写
    FSDataOutputStream fos = fs.create(new Path("/longge.txt"));
    //一边读一边写
    /*
        copyBytes(InputStream in, OutputStream out,int buffSize, boolean close)
        in : 输入流
        out : 输出流
        buffSize : 缓冲区大小  byte[] b = new byte[buffSize];
        close : 是否关闭资源
         */
    //        byte[] b = new byte[1024];
    //        int len = 0;
    //        while((len=fis.read(b)) != -1){
    //            fos.write(b,0,len);
    //        }
    IOUtils.copyBytes(fis,fos,1024,false);
    //关资源
    IOUtils.closeStream(fis);
    IOUtils.closeStream(fos);
}

3.2.8 通过流实现文件的下载

【案例】

@Test
public void test8() throws IOException {
    //读
    FSDataInputStream fis = fs.open(new Path("/longge.txt"));
    //写
    FileOutputStream fos = new FileOutputStream("D:\\io\\hdfs\\longge.txt");
    //文件对拷
    IOUtils.copyBytes(fis,fos,1024,true);
}

4 HDFS的数据流(面试重点)

4.1 HDFS写数据流程

4.1.1 剖析文件写入

(1) 客户端 --- Distribute FileSystem模块(请求上传文件)---> NameNode    NameNode检查目标文件、父目录是否存在

(2) NameNode 答复 (是否可以上传)

(3) 客户端 ---第一个Block传到哪?--->Namenode

(4) Namenode返回3个DataNode节点(dn1,dn2,dn3)

(5) 客户端 ---FSDataOutputStream模块(请求上传数据)--->dn1 ---调用--->dn2 ---调用--->dn3    通信管道建立完成

(6) dn1 ---应答成功---> dn2 ---应答成功---> dn3

(7) 客户端 ---上传(第一个block,单位Packet)--->dn1 ---分享Package--->dn2 ---分享Package--->dn3

(8) 当第一个Block传输完成后,客户端再次请求NameNode上传第二个Block的服务器(重复执行3-7)。

4.1.2 网络拓扑-节点距离计算

在HDFS写数据的过程中,NameNode会选择距离待上传数据最近距离的DataNode接收数据。

节点距离:两个节点到达最近的公共祖先的距离总和

4.1.3 机架感知-副本存储节点选择

1) 官方IP地址

2) Hadoop3.1.3副本节点选择

● 副本1:在Client所处节点上。如果客户端在集群外,随机选一个。

● 副本2:在另一个机架的随机一个节点

● 副本3:在副本2所在机架的随机节点

4.2 HDFS读数据流程

(1)  客户端 ---DIstributed FileSystem(请求下载文件)--->NameNode(权限匹配后,查询元数据,找到文件块的DataNode地址)

(2)  选择 ---(就近原则,随机)--->DataNode1 --->读取数据

(3) DataNode ---数据(传输)--->客户端      (从磁盘里面读取数据输入流,以packet为单位来校验)

(4) 客户端接收数据,在本地缓存,然后写入目标文件。(以Packet为单位)

 

5 NameNode和SecondaryNameNode(面试开发重点)

5.1 NN和2NN工作机制

1) 第一阶段:NameNode启动

(1) 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如不是第一次启动,直接加载编辑日志和镜像文件到内存。

(2) 客户端---对元数据的增删改(请求)--->NameNode

(3) NameNode记录操作日志,更新滚动日志

(4) NameNode在内存中对元数据进行增删改

2)第二阶段:Secondary NameNode工作

(1) Secondary NameNode询问NameNode是否须要CheckPoint。直接带回NameNode是否检查结果。

(2)  Secondary NameNode请求执行Checkoint。

(3) NameNode滚动正在写的Edits日志。

(4) 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode

(5) Secondary NameNode加载编辑日志和镜像文件到内存中,进行合并。

(6) 生成新的镜像文件fsimage.chkpoint。

(7) 拷贝fsimage.chkpoint到NameNode

(8) NameNode将fsimage.chkpoint重命名为fsiamge。

总结:

CheckPoint请求(2nn)——滚动日志Edits(nn)——拷贝(nn-2nn)——加载到内存合并(2nn)——fsimage.chkpoint(2nn-nn)——重命名为fsimage(nn)

【实例】

5.2 Fsimage和Edits解析

NameNode被格式化后,将在/opt/module/hadoop-3.1.3/data/dfs/namesecondary/current目录下生成如下文件。

Fsimage文件:永久性的检查点,其中包含HDFS文件系统的所有目录文件inode的序列化信息

Edits:存放所有更新操作的路径。文件系统客户端执行的所有写操作首先会被记录到Edits文件中。

seen_txid:保存的是一个数字,就是最后一个edits_的数字。

每次NameNode启动,都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以堪称NameNode启动的时候就将Fsimage和Edits文件进行了合并。

oiv 查看 Fsimage文件 hdfs oiv -p 文件类型 -i镜像文件 -o 转换后文件输出路径
oev 查看 Edits文件 hdfs oev -p 文件类型 -i编辑日志 -o 转换后文件输出路径

5.3 CheckPoint时间设置

5.4 NameNode故障处理

5.5 集群安全模式

 

6 DataNode(面试开发重点)

6.1 DataNode工作机制

(1) 一个数据块在DataNode以文件形式存储在磁盘上,包含两个文件:数据元数据

数据块:

● 数据本身

● 元数据 — 数据块的长度、校验和、时间戳。

(2)  DataNode启动后向NameNode注册,通过后,周期性(1小时)的向NameNode上报所有的块信息

(3) 心跳(3次/s,告诉nn我还或者)

● 心跳返回结果带有NameNode给该DataNode的命令块(如:复制块数据到另一台机器,删除某个数据块等)

● 如果超过10min+30s没有所有某个DataNode的心跳,则认为该节点不可用。

(4) 集权运行中可以安全加入和退出一些机器。

6.2 数据完整性

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

● 当DataNode读取Block的时候,它会计算CheckSum。

● 如果计算后的CheckSum,与Block创建时值不一样,说明Block已经损坏。

● C lient读取其他DataNode上的Block。

● DtaNode在其文件创建后周期验证CheckSum。

6.3 掉线时限参数设置

6.4 服役新数据节点

6.5 退役旧数据节点

6.5.1 添加白名单

6.5.2 黑名单退役

6.6 DataNode多目录配置

 

posted @ 2021-12-12 11:52  白森  阅读(81)  评论(0编辑  收藏  举报