HDFS总结

第一章 HDFS概述

1.1 HDFS产出背景及定义

1.1.1 HDFS背景

  • 随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS只是分布式文件管理系统中的一种。

1.1.2 HDFS定义

  • HDFS,是一个文件系统,用于存储文件,通过目录树来定位文件,其次,它是分布式的,由很多服务器联合起来实现其功能,其群众的服务器有各自的角色。
  • HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来作数据分析,并不适合用来作网盘应用。

1.2 HDFS的优缺点

1.2.1 优点

  • 高容错性
    • 数据自动保存多个副本,它通过增加副本的形式,提供容错性
    • 某一个副本丢失后,它可以自动恢复
  • 适合处理大数据
    • 数据规模:能够处理数据规模达到GB、TB、甚至PB的数据
    • 文件规模:能够处理百万规模以上的文件数量,数量相当之大
  • 可以构建在廉价机器上,通过多副本机制,提高可靠性

1.2.2 缺点

  • 不合适低延时数据访问,比如毫秒级的存储数据,是做不到的
  • 无法高效的对大量的小文件进行存储
    • 存储大量的小文件的话,它会占用NameNode大量的内存来存储文件目录和块信息。这样是不可取的,因为NameNode的内存总是有限的
    • 小文件存储的寻址时间会超过读取时间,他违反了HDFS的设计目标
  • 不支持并发写入、文件随机修改
    • 一个文件只能有一个写,不允许多个线程同时写
    • 仅支持数据append(追加),不支持文件的随机修改

1.3 HDFS组成架构

 

  • NameNode:就是Master,它是一个主管,管理者
    • 管理HDFS的名称空间
    • 配置副本策略
    • 管理数据块(Block)映射信息
    • 处理客户端读写数据
  • DataNode:就是Slave。NameNode下达命令,DataNode执行实际操作
    • 存储实际的数据块
    • 执行数据块的读/写操作

1.4 HDFS文件块大小

  • HDFS中文件在物理上是分块存储(Block),块的大小可以通过配置参数(dfs.blocksize)来规定,默认大小在Hadoop2.x版本中是128M
  • 寻址的时间为传输的时间的1%时,是最佳状态。

二、HDFS的Shell操作

2.1 基本语法

hadoop fs 具体命令
hdfs dfs 具体命令

2.2 命令大全

[hadoop@master ~]$ hadoop fs
Usage: hadoop fs [generic options]
        [-appendToFile <localsrc> ... <dst>]
        [-cat [-ignoreCrc] <src> ...]
        [-checksum <src> ...]
        [-chgrp [-R] GROUP PATH...]
        [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
        [-chown [-R] [OWNER][:[GROUP]] PATH...]
        [-copyFromLocal [-f] [-p] [-l] <localsrc> ... <dst>]
        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-count [-q] [-h] <path> ...]
        [-cp [-f] [-p | -p[topax]] <src> ... <dst>]
        [-createSnapshot <snapshotDir> [<snapshotName>]]
        [-deleteSnapshot <snapshotDir> <snapshotName>]
        [-df [-h] [<path> ...]]
        [-du [-s] [-h] <path> ...]
        [-expunge]
        [-find <path> ... <expression> ...]
        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-getfacl [-R] <path>]
        [-getfattr [-R] {-n name | -d} [-e en] <path>]
        [-getmerge [-nl] <src> <localdst>]
        [-help [cmd ...]]
        [-ls [-d] [-h] [-R] [<path> ...]]
        [-mkdir [-p] <path> ...]
        [-moveFromLocal <localsrc> ... <dst>]
        [-moveToLocal <src> <localdst>]
        [-mv <src> ... <dst>]
        [-put [-f] [-p] [-l] <localsrc> ... <dst>]
        [-renameSnapshot <snapshotDir> <oldName> <newName>]
        [-rm [-f] [-r|-R] [-skipTrash] <src> ...]
        [-rmdir [--ignore-fail-on-non-empty] <dir> ...]
        [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
        [-setfattr {-n name [-v value] | -x name} <path>]
        [-setrep [-R] [-w] <rep> <path> ...]
        [-stat [format] <path> ...]
        [-tail [-f] <file>]
        [-test -[defsz] <path>]
        [-text [-ignoreCrc] <src> ...]
        [-touchz <path> ...]
        [-truncate [-w] <length> <path> ...]
        [-usage [cmd ...]]

Generic options supported are
-conf <configuration file>     specify an application configuration file
-D <property=value>            use value for given property
-fs <local|namenode:port>      specify a namenode
-jt <local|resourcemanager:port>    specify a ResourceManager
-files <comma separated list of files>    specify comma separated files to be copied to the map reduce cluster
-libjars <comma separated list of jars>    specify comma separated jar files to include in the classpath.
-archives <comma separated list of archives>    specify comma separated archives to be unarchived on the compute machines.

The general command line syntax is
bin/hadoop command [genericOptions] [commandOptions]

2.3 常用命令

  • 启动Hadoop集群
[hadoop@master ~]$ start-dfs.sh 
Starting namenodes on [master]
master: starting namenode, logging to /opt/software/hadoop-2.7.2/logs/hadoop-hadoop-namenode-master.out
slave02: starting datanode, logging to /opt/software/hadoop-2.7.2/logs/hadoop-hadoop-datanode-slave02.out
slave01: starting datanode, logging to /opt/software/hadoop-2.7.2/logs/hadoop-hadoop-datanode-slave01.out
slave03: starting datanode, logging to /opt/software/hadoop-2.7.2/logs/hadoop-hadoop-datanode-slave03.out
Starting secondary namenodes [slave01]
slave01: starting secondarynamenode, logging to /opt/software/hadoop-2.7.2/logs/hadoop-hadoop-secondarynamenode-slave01.out
[hadoop@master ~]$ start-yarn.sh 
starting yarn daemons
starting resourcemanager, logging to /opt/software/hadoop-2.7.2/logs/yarn-hadoop-resourcemanager-master.out
slave01: starting nodemanager, logging to /opt/software/hadoop-2.7.2/logs/yarn-hadoop-nodemanager-slave01.out
slave02: starting nodemanager, logging to /opt/software/hadoop-2.7.2/logs/yarn-hadoop-nodemanager-slave02.out
slave03: starting nodemanager, logging to /opt/software/hadoop-2.7.2/logs/yarn-hadoop-nodemanager-slave03.out
  • -help:输出这个命令参数
[hadoop@master ~]$ hadoop fs -help rm
-rm [-f] [-r|-R] [-skipTrash] <src> ... :
  Delete all files that match the specified file pattern. Equivalent to the Unix
  command "rm <src>"
                                                                                 
  -skipTrash  option bypasses trash, if enabled, and immediately deletes <src>   
  -f          If the file does not exist, do not display a diagnostic message or 
              modify the exit status to reflect an error.                        
  -[rR]       Recursively deletes directories   
  • -ls:显示目录信息
[hadoop@master ~]$ hadoop fs -ls /
Found 8 items
-rw-r--r--   3 hadoop supergroup  289927651 2020-11-23 11:14 /Yuri_s_Revenge_1.001.exe
drwxr-xr-x   - hadoop supergroup          0 2020-11-25 13:40 /flowbean
drwxr-xr-x   - hadoop supergroup          0 2020-11-30 15:52 /input
-rw-r--r--   3 hadoop supergroup     603940 2020-11-23 10:43 /rename.pdf
drwxr-xr-x   - hadoop supergroup          0 2020-11-24 21:03 /test.har
drwxrwx---   - hadoop supergroup          0 2020-11-22 21:31 /tmp
drwxrwxrwx   - root   root                0 2020-11-25 12:45 /wordcount
-rw-r--r--   3 hadoop supergroup   10485760 2020-11-23 12:25 /算法笔记.胡凡.pdf
  • -mkdir:在HDFS上创建目录
[hadoop@master ~]$ hadoop fs -mkdir -p /sanguo/shuguo
  • -moveFromLocal:从本地剪切,粘贴到HDFS
[hadoop@master ~]$ hadoop fs -moveFromLocal data.txt /sanguo/sanguo
  • -appendToFile:追加一个文件到已经存在的文件末尾
[hadoop@master ~]$ hadoop fs -appendToFile liubei.txt /sanguo/shuguo/kongming.txt
  • cat:显示文件内容
[hadoop@master ~]$ hadoop fs -cat /sanguo/sanguo
hello   hi      hello   hi
hi      hello   i       am
fine    thanks  you
hi      fine    tha
  • -chgrp 、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
  • -copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
  • -copyToLocal:从HDFS拷贝到本地
  • -cp:从HDFS的一个路径拷贝到HDFS的另一个路径
  • -mv:在HDFS目录中移动文件
  • -get:等同于copyToLocal,就是从HDFS下载文件到本地
  • -getmerge:合并下载多个文件,比如HDFS的目录 /aaa/下有多个文件:log.1, log.2,log.3,...
[hadoop@master ~]$ hadoop fs -getmerge /wordcount/input/hi* /opt/software/hi.txt
  • -put:等同于copyFromLocal
  • -tail:显示一个文件的末尾
  • -rm:删除文件或文件夹
  • -rmdir:删除空目录
  • -du统计文件夹的大小信息
  • -setrep:设置HDFS中文件的副本数量,这里的副本数量只是记录在NameNode的元数据中,是否真的会有这么多的副本,还得看DataNode的数量。

三、HDFS客户端操作

3.1 HDFS环境配置

  • 根据自己电脑的操作系统拷贝对应的编译后的hadoop jar包到非中文路径
  • 配置HADOOP_HOME环境变量
  • 配置PATH环境变量
  • 创建一个Maven工程
  • 导入相应的依赖
<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>2.8.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-common</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-client</artifactId>
			<version>2.7.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-hdfs</artifactId>
			<version>2.7.2</version>
		</dependency> 
<dependency>
            <groupId>jdk.tools</groupId>
            <artifactId>jdk.tools</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
    </dependency>
		
</dependencies>

3.2 HDFS的API操作

3.2.1 HDFS的API基本操作

package cqupt.tiger.hdfs;

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;

/*
* 1、FileSystem:文件系统的抽象基类
*       FileSystem的实现取决于fs.defaultFS的配置
*   有两种实现!
*   LocalFileSystem:本地文件系统
*   DistributedFileSystem:分布式文件系统
*
*   声明用户身份
*
* 2、Configuration:功能是读取配置文件中的参数
*   Configuration在读取配置文件参数时,根据文件名,从类路径按照顺序读取配置文件
*       先读取xxx-default.xml,再读取xxx-site.xml
*   Configuration类一加载,就会默认读取8个配置文件
*   将8个配置文件中所有属性,读取到一个Map集合中
*   同时提供了set方法,来手动设置用户自定义的参数
*
* 3、FileStatus
*   代表一个文件的状态(文件的属性信息)
*
* 4、offset和length
*   offset:是偏移量:指块在我呢就爱你中的起始位置
*   length:是块的大小
*
* 5、LocatedFileStatus
*   LocatedFileStatus是FileStatus的子类,除了文件的属性,还有块的位置信息!
*
* */

public class TestHDFS {
    private FileSystem fs = null;
    private Configuration conf = null;

    @Before
    public void init() throws Exception {
        conf = new Configuration();


        // 创建一个客户端对象
        // FileSystem fs = FileSystem.get(conf);
        fs = FileSystem.get(new URI("hdfs://master:9000"), conf, "hadoop");

    }

    /*
    * hadoop fs(运行一个通用的用户客户端) -mkdir /xxx
    * 创建一个客户端对象,调用创建目录的方法,路径作为方法的参数传入
    * */
    @Test
    public void testMkdir() throws Exception {

        fs.mkdirs(new Path("/idea"));

    }

    // 上传文件
    @Test
    public void uploadFile() throws IOException {
        fs.copyFromLocalFile(false, true, new Path("/Users/shiwenhu/Downloads/Yuri_s_Revenge_1.001.exe"), new Path("/"));
    }

    // 下载文件
    @Test
    public void testDownload() throws IOException {
        fs.copyToLocalFile(false, new Path("/中国计算机学会推荐国际学术会议和期刊目录-2019.pdf"), new Path("/Users/shiwenhu/Desktop"), false);
    }

    // 删除文件:hadoop fs -rm -r -f 路径
    @Test
    public void testDelete() throws IOException {
        fs.delete(new Path("/idea"), true);
    }

    // 重命名: hadoop fs -mv 源文件 目标文件
    @Test
    public void testRename() throws IOException {
        fs.rename(new Path("/中国计算机学会推荐国际学术会议和期刊目录-2019.pdf"), new Path("/rename.pdf"));
    }

    // 判断当前路径是否存在
    @Test
    public void testIfPathExists() throws IOException {
        System.out.println(fs.exists(new Path("/idea")));
    }

    // 判断当前路径是目录还是文件
    @Test
    public void testFileIsDir() throws IOException {
        Path path = new Path("/rename.pdf");

        // 不建议使用此方法,建议使用FileStatus
        System.out.println(fs.isDirectory(path));
        System.out.println(fs.isFile(path));

        // 建议使用此方法
        FileStatus fileStatus = fs.getFileStatus(path);
        System.out.println("是否是目录:" + fileStatus.isDirectory());
        System.out.println("是否是文件:" + fileStatus.isFile());
    }

    // 返回当前目录及其子目录里面所有内容
    @Test
    public void testDirList() throws IOException {
        Path path = new Path("/wordcount");
        FileStatus[] fileStatuses = fs.listStatus(path);
        for (FileStatus fileStatus : fileStatuses) {
            // 获取文件名path是完整路径,包含协议+文件名
            Path fileStatusPath = fileStatus.getPath();
            System.out.println(fileStatusPath + "是否是目录:" + fileStatus.isDirectory());
            System.out.println(fileStatusPath + "是否是文件:" + fileStatus.isFile());
        }
    }

    // 获取文件的块信息
    @Test
    public void testGetBlockInformation() throws IOException {
        Path path = new Path("/Yuri_s_Revenge_1.001.exe");
        RemoteIterator<LocatedFileStatus> status = fs.listLocatedStatus(path);
        while(status.hasNext()) {
            LocatedFileStatus next = status.next();

            // 块的信息
            BlockLocation[] blockLocations = next.getBlockLocations();
            for (BlockLocation blockLocation : blockLocations) {
                System.out.println(blockLocation);
                System.out.println("----------------------------");
            }
        }

    }


    @After
    public void close() throws IOException {
        if (fs != null) {
            fs.close();
        }

    }


}

3.2.2 HDFS 的I/O流操作

package cqupt.tiger.hdfs;


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.net.URI;

/*
* 1、上传文件时,只上传这个文件的一部分
*
* 2、下载文件时,如何只下载文件的某一个块,或者只下载文件的一部分
*
* */
public class TestClientUploadAndDownload {
    private FileSystem fs = null;
    private FileSystem localFs = null;
    private Configuration conf = null;

    @Before
    public void init() throws Exception {
        conf = new Configuration();


        // 创建一个客户端对象
        // FileSystem fs = FileSystem.get(conf);
        fs = FileSystem.get(new URI("hdfs://master:9000"), conf, "hadoop");

        // 本地文件系统
        localFs = FileSystem.get(new Configuration());

    }

    // 只上传文件的前10M
    /*
    * 官方实现:
    *   contents = null;
            FSDataOutputStream out = null;

            try {
                InputStream in = srcFS.open(src);
                out = dstFS.create(dst, overwrite);
                IOUtils.copyBytes(in, out, conf, true);
            } catch (IOException var11) {
                IOUtils.closeStream(out);
                IOUtils.closeStream(contents);
                throw var11;
            }
    *
    * */
    @Test
    public void testClientUpload() throws Exception {
        // 提供两个Path,和两个FileSystem
        Path src = new Path("/Users/shiwenhu/Downloads/算法笔记.胡凡.pdf");
        Path dest = new Path("/算法笔记.胡凡.pdf");



        // 使用本地文件系统中的输入流来读取本地文件
        FSDataInputStream in = localFs.open(src);

        // 使用HDFS的分布式文件系统获取的输出流,向dest路径写入数据
        FSDataOutputStream out = fs.create(dest, true);

        // 1K
        // 流中数据拷贝
        byte[] buffer = new byte[1024];
        for (int i = 0; i < 1024 * 10; i++) {
            in.read(buffer);
            out.write(buffer);
        }

        // 关闭
        IOUtils.closeStream(in);
        IOUtils.closeStream(out);

    }

    // 自定义下载
    @Test
    public void testFirstBlock() throws IOException {
        // 提供两个Path和两个FileSystem
        Path src = new Path("/算法笔记.胡凡.pdf");
        Path dest = new Path("/Users/shiwenhu/Desktop/firstblock");

        // 使用HDFS的分布式文件系统获取输入流,读取HDFS上指定路径的数据
        FSDataInputStream in = fs.open(src);

        // 使用本地文件系统中获取的输出流写入本地文件
        FSDataOutputStream out = localFs.create(dest, true);

         //
        byte[] buffer = new byte[1024];
        for (int i = 0; i < 1024 * 128; i++) {
            in.read(buffer);
            out.write(buffer);
        }

        // 关闭
        IOUtils.closeStream(in);
        IOUtils.closeStream(out);

    }

    @Test
    public void testSecondBlock() throws IOException {
        // 提供两个Path和两个FileSystem
        Path src = new Path("/算法笔记.胡凡.pdf");
        Path dest = new Path("/Users/shiwenhu/Desktop/secondblock");

        // 使用HDFS的分布式文件系统获取输入流,读取HDFS上指定路径的数据
        FSDataInputStream in = fs.open(src);

        // 使用本地文件系统中获取的输出流写入本地文件
        FSDataOutputStream out = localFs.create(dest, true);

        // 定位到流的指定位置
        in.seek(1024 * 1024 * 128);

        //
        byte[] buffer = new byte[1024];
        for (int i = 0; i < 1024 * 128; i++) {
            in.read(buffer);
            out.write(buffer);
        }

        // 关闭
        IOUtils.closeStream(in);
        IOUtils.closeStream(out);
    }




    @After
    public void close() throws IOException {
        if (fs != null) {
            fs.close();
        }

    }


}

四、HDFS的数据流

4.1 HDFS写数据流程

4.1.1 文件写入

  • HDFS写数据流程,如下图:

  • 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标是否已经存在,父目录是否已存在
  • NameNode返回是否可以上传
  • 客户端请求上传第一个Block上传到哪几个DataNode服务器上
  • NameNode返回3个DataNode节点,分别为dn1,dn2,dn3
  • 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成
  • dn1,dn2,dn3逐级应答客户端
  • 客户端开始网dn1上传到第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答
  • 当一个Block传输完成之后,客户端再次请求NameNode长串第二个Block的服务器

4.1.2 机架感知(副本存储节点选择)

  • 第一个副本在Client所处的节点上,如果客户端在集群外,随机选择一个
  • 第二个副本和第一个副本位于相同机架,随机节点
  • 第三个副本位于不同机架,随机节点

4.2 HDFS读数据流程

4.2.1 HDFS读数据流程

  • HDFS读数据流程如下图所示:

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

五、NameNode和SecondaryNameNode

5.1 NameNode和SecondNameNode工作机制

5.1.1 工作流程

  • 第一阶段:NameNode启动
    • 第一次启动NameNode格式化后,创建Fsimage和Edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存
    • 客户端对元数据进行增删改的请求
    • NameNode记录操作日志,更新滚动日志
    • nameNode在内存中对数据进行增删改
  • 第二阶段
    • Secondary NameNode询问NameNode是否需要CheckPoint,直接带回NameNode是否检查结果
    • Secondary NameNode请求执行CheckPoint
    • 将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
    • Secondary NameNode 加载编辑日志和镜像文件到内存,并合并
    • 生成新的镜像文件fsimage.chkpoint
    • 拷贝fsimage.chkpoint到NameNode
    • NameNode将fsimage.chkpoint重命名为fsimage

5.1.2 NameNode和Secondary NameNode工作机制详解

  • fsimage:NameNode内存中元数据序列化后形成的文件
  • Edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。
  • NameNode启动时,先滚动Edits并生成一个空的edits.inprogress,然后加载Edits和Fsimage到内存中,此时NameNode内存就持有最新的元数据信息。Client开始对NameNode发送到元数据的增删改的请求,这些请求的操作首先会被记录到edits.inprogress中(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息),如果此时NameNode挂掉,重启后会从Edits中读取信息。然后,NameNode会在内存中执行元数据的增删改操作。
  • 由于Edits中记录的操作会越来越多,Edits文件就会越来越大,导致nameNode在启动加载Edits时会很慢,所以需要对Edits和Fsimage进行合并(所谓合并,就是将Edits和Fsimage加载到内存中,照着Edits中的操作一步步执行,最终形成新的Fsimage)
  • SecondaryNameNode的作用就是帮助NameNode进行Edits和Fsimage的合并工作
  • SecondaryNameNode首先会询问NameNode是否需要CheckPoint操作(触发CheckPoint需要满足两个条件中的任意一个,定时时间到和Edits中数据写满了)。直接带回nameNode是否检查结果。
  • SecondaryNameNode执行CheckPoint操作,首先会让NameNode滚动并生成一个空的Edits.inprogress,滚动Edits的目的是给Edits打个标记,以后所有新的操作都写入edits.inprogress,其他未合并的Edits和Fsimage会拷贝到SecondaryNameNode的本地,然后将拷贝的Edits和Fsimage加载到内存中进行合并,生成fsimage.chkpoint,然后将fsimage.chkpoint拷贝给NameNode,重命名为Fsimage后替换掉原来的Fsimage。
  • NameNode在启动时就只需要加载之前未合并的Edits和Fsimage即可,因为合并过的Edits中的元数据信息已经被记录在Fsimage中。

5.2 Fsimage和Edits解析

  • Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。
  • Edits文件:存放在HDFS文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到Edits文件中
  • seen_txid文件保存的是一个数字,就是最后一个edits_的数字
  • 每次nameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的元数据信息是最新的,同步的,可以看成NameNode启动的时候就将Fsimage和Edits文件进行了合并

5.3 CheckPoint时间设置

  • 通常情况下,SecondaryNameNode每隔一个小时执行一次,或者当操作次数达到1百万此时候执行,也可以通过配置hdfs-site.xml来配置
<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.4 NameNode故障处理

  • NameNode故障后,可以采用如下两种方法恢复数据

5.4.1 方法一

  • 将SecondaryNameNode中数据拷贝到NameNode存储数据的目录
    • kill掉NameNode进程
    • 删除NameNode存储的数据(/data/tmp/dfs/name)
    • 拷贝SecondaryNameNode中数据到原NameNode存储数据目录
    • 重新启动NameNode

5.4.2 方法二

  • 使用-importCheckpoint选项启动NameNode守护进程,从而将SecondaryNameNode中数据拷贝到NameNode目录中
  • 修改hdfs-site.xml中
property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>120</value>
</property>

<property>
    <name>dfs.namenode.name.dir</name>
    <value>/opt/software/hadoop-2.7.2/data/tmp/dfs/name</value>
</property>
  • kill掉NameNode进程
  • 删除NameNode存储的数据(/data/tmp/dfs/name)
  • 如果SecondaryNameNode不和NameNode在一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到NameNode存储数据的平级目录,并删除in_use.lock文件
  • 导入检查点数据(等一会ctrl+c结束)
  • 启动NameNode

5.5 集群安全模式

5.5.1 概述

  • NameNode启动:首先将镜像文件(Fsimage)载入内存,并执行编辑日志(Edits)中的各项操作,一旦在内存中成功建立文件系统元数据的映像,则创建一个新的Fsimage文件和一个空的编辑日志,此时,NameNode开始监听DataNode请求。这个过程期间,nameNode一直运行在安全模式,即NameNode的文件系统对于客户端来说是只读的
  • DataNode启动:系统中的数据块的位置并不是由NameNode维护的,而是以块列表的形式存储在DataNode中,在系统正常操作期间,NameNode会在内存中保留所有块位置的映射信息,在安全模式下,各个DataNode会向NameNode发动最新的块信息列表信息,NameNode了解到足够多的块位置信息后,即可高效运行文件系统
  • 安全模式退出判断:如果满足“最小副本条件”,NameNode会在30秒钟之后就退出安全模式,所谓的最小副本条件指的是在整个文件系统中99.9%的块满足最小副本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以NameNode不会进入安全模式

5.5.2 基本语法

  • hdfs dfsadmin -safemode get:查看安全模式状态
  • hdfs dfsadmin -safemode enter:进入安全模式状态
  • hdfs dfsadmin -safemode leave:离开安全模式状态
  • hdfs dfsadmin -safemode wait:等待安全模式状态

5.6 NameNode多目录配置

  • NameNode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性,具体配置如下:
  • 在hdfs-site.xml文件中增加如下内容
<property>
    <name>dfs.namenode.name.dir</name>  
    <value>file:///${hadoop.tmp.dir}目录1,file:///${hadoop.tmp.dir}目录2</value>
</property>
  • 停止集群,删除data和logs中的所有数据
  • 格式化集群并启动

六、DataNode

6.1 DataNode工作机制

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

6.2 数据的完整性

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

6.3 掉线参数设置

  • DataNode进程死亡或者网络故障导致DataNode无法与NameNode通信
  • NameNode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称为超时时长
  • HDFS默认的超时时长为10min+30s
  • 如果定义超时时间为TimeOut,则超时时长计算公式如下:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
# 默认的dfs.namenode.heartbeat.recheck-interval大小为5min,dfs.heartbeat.interval默认为3s
  • 需要注意的是hdfs-site.xml配置文件中的dfs.heartbeat.interval的单位为毫秒,dfs.namenode.heartbeat.recheck-interval的单位为秒
<property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
</property>
<property>
    <name> dfs.heartbeat.interval </name>
    <value>3</value>
</property>

6.4 服役新数据节点

  • 直接启动DataNode,即可关联到集群
[hadoop@master software]$ hadoop-daemon.sh start datanode
[hadoop@master software]$ yarn-daemon.sh start nodemanager
  • 如果数据不平衡,可以使用命令实现集群再平衡
[hadoop@master software]$ start-balancer.sh

6.5 退役旧数据节点

6.5.1 添加白名单

  • 添加到白名单的主机,都允许访问NameNode,不在白名单的主机,都会被退出,具体步骤如下;
  • 在NameNode的/opt/software/hadoop-2.7.2/etc/hadoop目录下面创建dfs.hosts文件,在文件中添加相应的主机名
  • 在NameNode的hdfs-site.xml配置文件中增加dfs.hosts属性
<property>
    <name>dfs.hosts</name>
    <value>/opt/software/hadoop-2.7.2/etc/hadoop/dfs.hosts</value>
</property>
  • 将修改后的hdfs-site.xml文件分发给每一个节点
  • 刷新NameNode
[hadoop@master software]$ hdfs dfsadmin -refreshNodes
  • 更新ResourceManager节点
[hadoop@master software]$ yarn rmadmin -refreshNodes
  • 如果数据不均衡,可以用命令实现集群的再平衡
[hadoop@master software]$ start-balancer.sh

6.5.2 黑名单退役

  • 在黑名单上面的主机都会被强制退出
  • 在NameNode的/opt/software/hadoop-2.7.2/etc/hadoop目录下创建dfs.hosts.exclude文件
  • 添加要退役的节点
  • 在NameNode的hdfs-site.xml配置文件中增加dfs.hosts.exclude属性
<property>
    <name>dfs.hosts.exclude</name>
    <value>/opt/software/hadoop-2.7.2/etc/hadoop/dfs.hosts.exclude</value>
</property>
  • 刷新NameNode、刷新ResourceManager
[hadoop@master software]$ hdfs dfsadmin -refreshNodes
[hadoop@master software]$ yarn rmadmin -refreshNodes
  • 检查Web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点。
  • 等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役。
  • 如果数据不均衡,可以用命令实现集群的再平衡
[hadoop@master software]$ start-balancer.sh 

注意:不允许白名单和黑名单中同时出现一个主机名称。

6.6 DataNode多目录配置

  • DataNode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本。
  • 修改hdfs-site.xml配置
<property>
    <name>dfs.datanode.data.dir</name>
    <value>file:///${hadoop.tmp.dir}目录1,file:///${hadoop.tmp.dir}目录2</value>
</property>

七、HDFS 2.x新特性

7.1 集群间数据拷贝

  • scp实现两个远程主机之间的文件复制
  • 采用distcp命令实现两个Hadoop集群之间的递归数据复制
hadoop distcp 待拷贝URI 目标URI

7.2 Hadoop存档

  • HDFS存储小文件的弊端
    • 每个文件均按块存储,每个块的元数据在NameNode的内存中,因此Hadoop存储文件会非常低效。因为大量小文件会耗尽NameNode中的大部分内存。但注意,存储小文件所需要的磁盘容量和数据块大小无关。
  • 解决存储小文件办法之一
    • Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少NameNode内存使用的同时,允许对文件进行透明的访问。具体来说Hadoop存档文件对内还是一个一个独立文件,对NameNode而言却是一个整体,减少了NameNode的内存消耗
  • 案例:把/input目录里面的所有文件归档称为一个input.har归档文件,并把归档后文件存储到/output路径下
[hadoop@master software]$ hadoop archive -archiveName input.har –p /input /output
  • 查看归档
[hadoop@master software]$ hadoop fs -lsr /output/input.har
[hadoop@master software]$ hadoop fs -lsr har:///output/input.har
  • 解归档文件
[hadoop@master software]$ hadoop fs -cp har:///output/input.har/* /user/test

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值