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

public class HdfsClient{	
@Test
public void testMkdirs() throws IOException, InterruptedException, URISyntaxException{
		
		// 1 获取文件系统
		Configuration configuration = new Configuration();
		// 配置在集群上运行
		// configuration.set("fs.defaultFS", "hdfs://hadoop102:8020");
		// FileSystem fs = FileSystem.get(configuration);

		FileSystem fs = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "atguigu");
		
		// 2 创建目录
		fs.mkdirs(new Path("/1108/daxian/banzhang"));
		
		// 3 关闭资源
		fs.close();
	}
}

7) 创建HdfsClient类

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

3.2.1 HDFS文件上传

查看代码
@Test
public void test() throws URISyntaxException, IOException, InterruptedException {
  /*
        copyFromLocalFile(boolean delSrc, boolean overwrite,
                                Path src, Path dst)
          delSrc : 是否删除源文件(本地)
          overwrite : 如果目标文件存在是否覆盖。
                       true : 覆盖
                       false :不覆盖,但是如果目标文件存在则报错
           src : 源文件路径(本地)
           dst : 目标文件路径(HDFS)
         */
  fs.copyFromLocalFile(true,true,
                       new Path("D:\\io\\hdfs\\longge.txt"),new Path("/"));
}

 3.2.2 HDFS文件上传

查看代码
@Test
public void test2() throws IOException {
  /*
        copyToLocalFile(boolean delSrc, Path src, Path dst,boolean useRawLocalFileSystem)
        delSrc : 是否删除源文件(HDFS)
        src : 源文件路径(HDFS)
        dst : 目标文件路径(本地)
        useRawLocalFileSystem : 是否使用RawLocalFileSystem文件系统
                true : 本地不会生成crc校验和文件
                false : 本地会生crc校验和文件
         */
  fs.copyToLocalFile(false,new Path("/longge.txt"),
                     new Path("D:\\io\\hdfs"),false);
}

 3.2.3 HDFS文件夹删除

查看代码
@Test
public void test3() throws IOException {
  /*
            delete(Path f, boolean recursive)
            f : 路径
            recursive : 是否递归。
                   如果是文件true和false都可以。
                   如果是目录必须为true(空目录也可以是false).
         */
  fs.delete(new Path("/longge"),false);
}

 3.2.4 HDFS文件夹更改

查看代码
@Test
public void test4() throws IOException {
  /*
        rename(Path src, Path dst)
        src : 源文件路径
        dst : 目标文件路径
         */
  //        fs.rename(new Path("/input/b.txt"),new Path("/input/cc.txt"));
  //移动文件
  fs.rename(new Path("/input/cc.txt"),new Path("/input2"));
}

 3.2.5 HDFS文件详情查看

查看代码
@Test
public void test5() throws IOException {
  /*
        listFiles(final Path f, final boolean recursive)
        f : 路径
        recursive :是否递归
         */
  /*
        RemoteIterator : 迭代器--用来迭代所有的文件
         */
  RemoteIterator 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));
  }
}

 3.2.6 HDFS文件和目录判断

查看代码
@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() + "是一个目录");
    }
  }
}

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多目录配置

相关