1. HDFS简介

Hdoop Distribute File System,Hadoop分布式文件系统时Hadoop的核心组成部分,实现分布式存储服务。
分布式文件系统横跨多台计算机,为存储和处理超大规模数据提供扩展能力。
HDFS通过统一的命名空间目录树来定位文件,集群中的服务器各司其职,主要有以下特点:

  • 典型的master/slave架构

NameNode(一般一个,HA架构有两个)+DataNode(多个)组成

  • 分块存储(block机制)

HDFS中的文件在物理上是分块存储的,块的大小默认是128MB

  • 命名空间

提供给客户一个抽象目录树
web访问形式:http://192.168.80.101:50070/explorer.html#/
Linux访问形式:hdfs://hostname(NameNode):port/
NameNode负责维护文件系统的命名空间,任何对文件系统名字空间或属性的修改都将被NameNode记录下 来。

  • NameNode元数据管理

目录结构及文件分块位置叫做元数据,分块位置namenode不保存在磁盘中,由DataNode定时汇报,存储在 内存中。

  • DataNode数据存储

DataNode存储文件的各个block,由于副本机制,一个block会有多个DataNode存储,防止文件丢失,默认
副本数量是3,即包含原始数据,总共3份。

  • 一次写入,多次读出

HDFS是设计成适应一次写入,多次读出的场景,支持追加写入,不支持随机修改。

2. HDFS架构

image.png

  • NameNode(nn)
    • 维护命名空间
    • 维护副本策略
    • 记录文件块的映射信息
    • 负责处理客户端的读写请求
  • DataNode(dn)
    • 执行NameNode的命令
    • 保存实际的数据块
    • 负责数据块的读写
  • Client:客户端
    • 上传文件到HDFS的时候,Client负责将文件切分成Block,然后上传
    • 与NameNode交互,获取文件的位置信息
    • 读取或写入文件,与DataNode交互
    • Client可以使用一些命令来管理HDFS或者访问HDFS

3. 客户端操作

3.1 shell命令行

  1. hadoop fs commend #旧版本命令
  2. hdfs dfs commend # 新版本命令

部分命令演示

#输出命令的参数
hadoop fs -help rm
#显示目录信息
hadoop fs -ls
#在hdfs上创建目录
hadoop fs -mkdir -p /lagou/bigdata
#从本地剪切到hdfs
hadoop fs -moveFromLocal ./hadoop.txt /lagou/bigdata
#追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile hdfs.txt /lagou/bigdata/hadoop.txt
#从本地文件系统上传到hdfs
hadoop fs -copyFromLocal a.txt /lagou
hadoop fs -put a.txt /lagou
#从hdfs下载到本地
hadoop fs -copyToLocal /lagou/bigdata/a.txt ./
hadoop fs -get /lagou/bigdata/a.txt ./
#在hafs中拷贝文件
hadoop fs -cp /lagou/hadoop.txt /lagou2/hdfs.txt
#设置某个文件的副本数量
hadoop fs -setrep 10 /lagou/bigdata/hadoop.txt  
// 具体由多少副本需要看DataNode的数量,现在只有3个datanode,则只有3个副本,当datanode扩展到10个时,副本数会增长到10

3.2Java客户端

window端安装Hadoop注意事项

  1. 需要安装jdk8
  2. 解压hadoop-2.9.2.tar.gz到非中文路径的安装目录下
  3. 配置HADOOP_HOME环境变量
  4. 把winutils.exe放到hadoop安装目录的bin目录里winutils.zip
  5. 把hadoop.dll放入C:\Windows\System32hadoop.zip

    API操作

    参数优先级排序:代码中设置的值>用户自定义配置文件>服务器的默认配置
    原因在于覆盖,首先加载了默认配置.xml,然后加载自定义的.xml,最后代码中设置,后来的把前面覆盖了 ```java public class HDFSClient {

    @Test public void upload() throws URISyntaxException, IOException, InterruptedException {

     // 1.获取文件系统
     Configuration conf = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://centos7-1:9000"), conf, "root");
     // 2. 创建目录
     fs.mkdirs(new Path("/lagou/bigdata"));
     // 3.上传文件
     fs.copyFromLocalFile(new Path("e:/a.txt"),new Path("/lagou/bigdata/"));
     // 4.关闭资源
     fs.close();
     System.out.println("end");
    

    }

}

<a name="eO4sv"></a>
### IO流操作
创建本地文件的IO流<br />FileInputStream, FileOutputStream<br />创建HDFS文件的IO流<br />FSDataOutputStream fos = fs.create()<br />FSDataInputStream fis = fs.open()
```java
 public void putFileToHDFS() throws URISyntaxException, IOException, InterruptedException {
        // 1.获取文件系统
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://centos7-1:9000"), conf, "root");
        // 2.创建输入流
        FileInputStream fis = new FileInputStream(new File("E:\\hadooptest\\b.txt"));
        // 3.创建输出流 路径必须要给出名字,不能给到上一级目录
        FSDataOutputStream fos = fs.create(new Path("/lagou/bigdata/b.txt"));
        // 4.流对拷
        IOUtils.copyBytes(fis,fos,conf);
        // 5.关闭资源
        IOUtils.closeStream(fis);
        IOUtils.closeStream(fos);
        fs.close();
        System.out.println("end");
    }

4. HDFS读写解析

4.1 HDFS读数据流程

image.png

  1. 客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址(由于副本的存在,会有多个地址)
  2. 客户端挑选一台DataNode(就近原则,然后随机),请求读取数据
  3. DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以packet(默认64KB)为单位来做校验)
  4. 客户端以packet为单位接收,先在本地缓存,然后写入目标文件

    4.2 HDFS写数据流程

    image.png

  5. 客户端通过DFS模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在

  6. NameNode返回是否可以上传
  7. 客户端请求第一个block上传到哪几个DataNode服务器上
  8. NameNode返回3个DataNode节点,分别为dn1、dn2、dn3
  9. 客户端通过FSDataOutputStream模块请求向dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成
  10. dn1、dn2、dn3逐级应答客户端
  11. 客户端开始往dn1上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,dn1收到一个packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个确认队列等待确认
  12. 当一个block传输完成之后,客户端再次请求NameNode上传第二个block的服务器(重复执行3-7步)

    5. NN与2NN

    5.1 HDFS元数据管理机制

    image.png
  • 第一阶段:NameNode启动
    • 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存
    • 客户端对元数据进行增删改的请求
    • NameNode记录操作日志,更新滚动日志
    • NameNode在内存中对数据进行增删改
  • 第二阶段:Secondary NameNode工作

    • 2nn询问nn是否需要checkpoint
    • 2nn请求执行checkpoint
    • nn滚动正在写的Edits日志,例如封存edits_001,之后的操作记录在edits_inprogress_002上
    • 将滚动前的日志与fsimage文件拷贝到2nn
    • 生成新的镜像文件fsimage.chkpoint
    • 拷贝fsimage.chkpoint到nn
    • nn将fsimage.chkpoint重新命名成fsimage,覆盖以前的文件

      5.2 Fsimage与Edits文件解析

      NameNode在执行格式化之后,会在/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current ⽬录下产⽣如下⽂件
      image.png
  • fsimage文件:是namenode中关于元数据的镜像,⼀般称为检查点,这⾥包含了HDFS⽂件系统 所有⽬录以及⽂件相关信息(Block数量,副本数量,权限等信息)

  • Edits⽂件 :存储了客户端对HDFS⽂件系统所有的更新操作记录,Client对HDFS⽂件系统所有的 更新操作都会被记录到Edits⽂件中(不包括查询操作)
  • seen_txid:该⽂件是保存了⼀个数字,数字对应着最后⼀个Edits⽂件名的数字
  • VERSION:该⽂件记录namenode的⼀些版本号信息,⽐如:CusterId,namespaceID等

NameNode启动时会将Fsimage⽂件加载到内存中,同时也把之前未合并元数据的Edits⽂件加载,集 合两个⽂件中的元数据这样保证了NameNode中的元数据是最新最全的。通俗点说就是NameNode启 动时把Fsimage和Edits⽂件进⾏了合并。

5.2.1 Fsimage文件内容

官方地址

https://hadoop.apache.org/docs/r2.9.2/hadoop-project-dist/hadoophdfs/HdfsImageViewer.html

查看fsimage文件内容
oiv Offline Image Viewer

hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径
hdfs oiv -p XML -i fsimage_0000000000000000265 -o /opt/lagou/servers/fsimage.xml
cat /opt/lagou/servers/fsimage.xml

Fsimage中没有记录块所对应的DataNode,在集群启动后,NameNode要求DataNode上报数据块信息,并间隔一段时间再次上报

5.2.2 Edits文件内容

oev Offline edits viewer

hdfs oev -p 文件类型 -i 日志 -o 转换后文件输出路径
hdfs oev -p XML -i edits_0000000000000000266-0000000000000000267 -o /opt/lagou/servers/edits.xml
cat /opt/lagou/servers/edits.xml

edits中只记录了更新相关的操作,查询或下载文件不会记录在内
问题:NameNode启动时如何确定加载哪些Edits⽂件呢?
需要借助fsimage⽂件最后数字编码,来确定哪些edits之前是没有合并到fsimage中,启动时只需要加 载那些未合并的edits⽂件即可。

6. NN故障处理

NameNode故障后,HDFS集群就⽆法正常⼯作,因为HDFS文件系统的元数据需要由NameNode来管理维护并与Client交互,如果元数据出现损坏和丢失同样会导致NameNode⽆法正常⼯作进而HDFS文件系统⽆法正常对外提供服务。
如果元数据出现丢失损坏如何恢复呢?

  • 将2NN的元数据拷⻉到NN的节点下,此种⽅式会存在元数据的丢失。丢失了未合并的edits数据
  • 搭建HDFS的HA(⾼可⽤)集群,解决NN的单点故障问题!!(借助Zookeeper实现HA,⼀个 Active的NameNode,⼀个是Standby的NameNode)

    7. 限额、归档及集群安全模式

  • HDFS文件限额配置

HDFS⽂件的限额配置允许我们以⽂件⼤小或者⽂件个数来限制我们在某个目录下上传的⽂件数量或者文件内容总量,以便达到我们类似百度网盘网盘等限制每个用户允许上传的最⼤的⽂件的量

  1. 数量限额

    hdfs dfsadmin -setQuota 2 /user/root/lagou # 给该⽂件夹下⾯设置最多上传
    两个⽂件,上传⽂件,发现只能上传⼀个⽂件
    hdfs dfsadmin -clrQuota /user/root/lagou # 清除⽂件数量限制
    
  2. 空间大小限额

    hdfs dfsadmin -setSpaceQuota 4k /user/root/lagou # 限制空间⼤⼩4KB
    #上传超过4Kb的⽂件⼤⼩上去提示⽂件超过限额
    hdfs dfs -put /export/softwares/xxx.tar.gz /user/root/lagou
    hdfs dfsadmin -clrSpaceQuota /user/root/lagou #清除空间限额
    #查看hdfs⽂件限额数量
    hdfs dfs -count -q -h /user/root/lagou
    
  • 安全模式

安全模式是HDFS所处的⼀种特殊状态,在这种状态下,⽂件系统只接受读数据请求,⽽不接受删除、修改等变更请求。在NameNode主节点启动时,HDFS⾸先进⼊安全模式,DataNode在启动的时候会向NameNode汇报可⽤的block等状态,当整个系统达到安全标准时,HDFS⾃动离开安全模式。如果HDFS处于安全模式下,则⽂件block不能进⾏任何的副本复制操作,因此达到最⼩的副本数量要求是基于DataNode启动时的状态来判定的,启动时不会再做任何复制(从而达到最小副本数量要求),HDFS集群刚启动的时候,默认30S钟的时间是出于安全期的,只有过了30S之后,集群脱离了安全期,然后才可以对集群进⾏操作。

  • 归档技术

主要解决HDFS集群存在⼤量小文件的问题!! 由于大量小文件会占用NameNode的内存,因此对于HDFS来说存储大量小文件造成NameNode 内存资源的浪费! Hadoop存档文件HAR⽂件,是⼀个更⾼效的文件存档⼯具,HAR文件是由⼀组文件通过archive⼯ 具创建⽽来,在减少了NameNode的内存使⽤的同时,可以对⽂件进⾏透明的访问,通俗来说就 是HAR⽂件对NameNode来说是⼀个⽂件减少了内存的浪费,对于实际操作处理⽂件依然是⼀个个独立的文件。
案列
把/user/lagou/input⽬录里面的所有⽂件归档成⼀个叫input.har的归档⽂件,并把归档后⽂件存储到/user/lagou/output路径下。

hadoop archive -archiveName input.har –p /user/root/input /user/root/output

// 查看归档文件
hadoop fs -lsr /user/root/output/input.har
hadoop fs -lsr har:///user/root/output/input.har

// 解压归档文件
hadoop fs -cp har:///user/root/output/input.har/* /user/root