目录

一、概述

1、定义

2、特点

3、核心架构(主从架构)

4、特性

5、优缺点

6、架构

7、文件快大小

二、shell操作

1、基本语法

2、查看所有命令

3、命令实操

三、客户端操作

1、客户端环境准备

(1)编译Hadoop源码

(2)配置环境变量

(3)工程搭建

2、API操作

(1)创建目录

(2)文件上传

(3)文件下载

(4)文件名更改

(5)查看文件详情

(6) 文件和文件夹判断

3、I/O流操作

(1)文件上传

(2)文件下载

(3)文件读取

四、数据读写流程

1、数据写入

(1)写入流程

(2)副本节点选择

2、数据读取

五、NameNode和SecondaryNameNode

1、NN与2NN工作机制

(1)由来

(2)工作机制

(3)工作机制详解

2、Fsimage和Edits解析

(1)说明

(2)oiv查看Fsimage文件

1)基本语法

2)使用

 (3)oev查看Edits文件

1)基本语法

2)使用

3、 chkpoint时间设置

4、NameNode故障处理

(1)方式一

(2)方式二

5、集群安全模式

(1)概述

(2)基本语法

6、NameNode多目录配置

六、DataNode

1、工作机制

2、数据完整性

3、掉线时限参数设置

4、服役新数据节点

(1)准备工作

(2)具体操作

5、退役数据节点

(1)添加白名单

(2)黑名单退役

6、Datanode多目录配置

七、HDFS 2.X新特性

1、集群间数据拷贝

2、小文件存档

(1)存储小文件的弊端

(2)解决方案

(3)步骤

3、回收站

4、快照管理


一、概述

1、定义

1HDFS(Hadoop Distributed File System)是 Apache Hadoop 生态的核心组件之一,是专门为海量数据存储设计的分布式文件系统。你可以把它理解成 “大数据时代的分布式超级硬盘”—— 它将超大文件切分成小块,分散存储在集群的多台廉价商用服务器上,同时对外提供统一的文件访问接口,让用户感觉就像使用本地文件系统一样。

2、特点

        处理超大文件:主打 GB/TB/PB 级大文件存储,而非大量小文件(小文件会消耗核心节点内存,影响性能);

        高吞吐量访问:优先保证批量读取数据的效率(比如数据分析),而非低延迟的随机读写;

        高容错性:通过数据副本机制,即使部分服务器故障,数据也不会丢失;

        低成本部署:可运行在普通 x86 服务器上,无需高端硬件,降低集群搭建成本。

3、核心架构(主从架构)

HDFS 采用经典的 “主从架构”,核心由 3 个组件构成,分工明确:

组件角色定位核心功能
NameNode(名称节点)集群 “大脑”(主节点)1. 管理文件系统的命名空间(目录结构、文件名、权限等元数据);2. 记录文件块(Block)的存储位置;3. 协调 DataNode 的操作(创建 / 删除 / 复制块)。
DataNode(数据节点)集群 “手脚”(从节点)1. 实际存储数据块(Block);2. 执行 NameNode 的指令;3. 定期向 NameNode 汇报自身存储的块信息。
SecondaryNameNode集群 “助手”(非备机)1. 定期合并 NameNode 的元数据日志(EditLog)和镜像文件(FsImage);2. 减少 NameNode 重启时的加载时间,避免日志文件过大。(HA 模式下被 JournalNode 替代)

4、特性

        数据分块存储:大文件会被切分成固定大小的 “块(Block)”(Hadoop 2.x + 默认 128MB,可配置),每个块分散存储在不同 DataNode 上;

        副本容错机制:每个数据块默认复制 3 份(可配置),副本会分配在不同节点 / 机架(比如 1 份在本地机架,2 份在其他机架),即使某台服务器 / 机架故障,数据也不丢失;

        一次写入、多次读取(WORM):文件写入后(除非删除)不支持修改,仅支持追加写入,简化了数据一致性的维护;

        机架感知:HDFS 知道每个节点所在的机架,副本分配时优先考虑机架位置,减少跨机架网络传输,提升读写性能;

        元数据内存化:NameNode 将所有文件的元数据(目录、块信息等)存在内存中,保证元数据的快速访问(这也是 HDFS 不适合大量小文件的原因:小文件元数据会耗尽 NameNode 内存)。

5、优缺点

优点

  • 大数据批处理:如 Spark/MapReduce/Hive 处理海量日志、电商交易数据、用户行为数据;
  • 海量数据归档 / 备份:存储长期保留的原始数据(如监控日志、卫星数据);
  • 流媒体存储:存储视频、音频等大文件,提供高吞吐量访问。

缺点

  • 低延迟访问:如毫秒级响应的 OLTP 业务(比如电商下单、银行转账);
  • 大量小文件存储:小文件会占用 NameNode 大量内存,导致集群性能下降;
  • 频繁随机写:不支持对文件内容的频繁修改(比如数据库的更新操作)。

6、架构

(1)client客户端

        1)文件切分。文件上传 HDFS 时,Client 将文件切分成一个一个的Block,然后进行存储。

        2)与NameNode交互,获取文件的位置信息。

        3)与DataNode交互,读取或者写入数据。

        4)Client提供一些命令来管理HDFS,比如启动或者关闭HDFS。

        5)Client可以通过一些命令来访问HDFS。

(2)NameNode

        它是一个主管、管理者Master。

        1)管理HDFS的名称空间。

        2)管理数据块(Block)映射信息

        3)配置副本策略

        4)处理客户端读写请求。

(3)DataNode

        Slave,NameNode下达命令,DataNode执行实际的操作。

        1)存储实际的数据块。

        2)执行数据块的读/写操作。

(4)SecondaryNameNode

        并非NameNode的热备。当NameNode挂掉,它并不能马上替换NameNode并提供服务。

        1)辅助NameNode,分担其工作量。

        2)定期合并Fsimage和Edits,并推送给NameNode。

        3)在紧急情况下,可辅助恢复NameNode。

7、文件快大小

        HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M。
        HDFS的块比磁盘的块大,其目的是为了最小化寻址开销。如果块设置得足够大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间。因而,传输一个由多个块组成的文件的时间取决于磁盘传输速率。
        如果寻址时间约为10ms,而传输速率为100MB/s,为了使寻址时间仅占传输时间的1%,要将块大小设置约为100MB。默认的块大小128MB。
块的大小:10ms*100*100M/s = 100M

注意:

        1)如果HDFS的块设置太小,会增加寻址时间

        2)如果块设置的太大,从磁盘传输数据的时间会大于定位这个块开始位置所需的时间,导致程序处理这个块数据时非常慢

        3)HDFS块的大小取决于磁盘的传输速率

二、shell操作

1、基本语法

hadoop fs 具体命令

或者

hdfs dfs 具体命令

2、查看所有命令

 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.

3、命令实操

(1)-help:输出这个命令参数

例如:查看rm命令需要的参数

 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 

(2)-ls: 显示目录信息

例如:显示/目录下的文件或文件夹

hadoop fs -ls /

(3)-mkdir:在hdfs上创建目录

例如:在/目录下创建一个user/hk文件夹

hadoop fs -mkdir -p /user/hk

(4)-moveFromLocal从本地剪切粘贴到hdfs

例如:将本地的input/test.txt文件剪切到hdfs的/user/hk文件夹下

hadoop fs -moveFromLocal input/test.txt /user/hk/

(5)-appendToFile  :追加一个文件到已经存在的文件末尾

例如:将本地的input/test.txt文件追加到hdfs的/user/hk/test.txt文件下

hadoop fs -appendToFile input/test.txt /user/hk/test.txt

(6)-cat :显示文件内容

例如:查看/user/hk/test.txt文件内容

hadoop fs -cat /user/hk/test.txt

(7)-tail:显示一个文件的末尾

例如:查看/user/hk/test.txt文件的尾部内容

hadoop fs -tail  /user/hk/test.txt

(8)-chgrp 、-chmod、-chown:linux文件系统中的用法一样,修改文件所属权限

例如:修改/user/hk/test.txt文件的权限和归属

hadoop fs -chmod 666 /user/hk/test.txt

hadoop fs -chown hdhk:hdhk /user/hk/test.txt

(9)-copyFromLocal:从本地文件系统中拷贝文件到hdfs路径去

例如:将 README.txt文件拷贝到/user/hk里面

hadoop fs -copyFromLocal README.txt /user/hk

(10)-copyToLocal:从hdfs拷贝到本地

例如:将/user/hk/README.txt拷贝到 input/里面

hadoop fs -copyToLocal /user/hk/README.txt input/

(11)-cp :从hdfs的一个路径拷贝到hdfs的另一个路径

例如:将/user/hk/README.txt拷贝到 /user/input/里面

hadoop fs -cp /user/hk/README.txt /user/input/

(12)-mv:在hdfs目录中移动文件

例如:将/user/hk/README.txt移动到 /user/input/里面

hadoop fs -mv /user/hk/README.txt /user/input/

(13)-get:等同于copyToLocal,就是从hdfs下载文件到本地

例如:将/user/hk/README.txt下载到 input/里面

hadoop fs -get /user/hk/README.txt input/

(14)-getmerge  :下载多个hdfs文件合并到本地的一个文件里面

例如:将/user/hk/下的所有文件下载合并到 input/hello.txt里面

hadoop fs -getmerge /user/hk input/hello.txt

可以将多个日志文件合并成一个文件

(15)-put:从本地文件系统中拷贝文件到hdfs路径去,等同于copyFromLocal

例如:将 README.txt文件拷贝到/user/hk里面

hadoop fs -put README.txt /user/hk

(16)-rm:删除文件或文件夹

例如:删除/user/hk的README.txt文件

hadoop fs -rm /user/hk/README.txt

删除文件夹和文件

hadoop fs -rm -r /user/hk

(17)-rmdir:删除空目录

例如:/user/hk文件夹下如果没有文件,删除hk文件夹

hadoop fs -rmdir /user/hk

(18)-du统计文件夹的大小信息

例如:统计/user/hk文件夹的大小

hadoop fs -du /user/hk

hadoop fs -du -h /user/hk

hadoop fs -du -s -h /user/hk

(19)-setrep:设置hdfs中文件的副本数量

例如:设置/user/hk/test.txt的副本数为2

 hadoop fs -setrep 2 /user/hk/test.txt

        这里设置的副本数只是记录在namenode的元数据中,是否真的会有这么多副本,还得看datanode的数量。因为有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。

三、客户端操作

1、客户端环境准备

(1)编译Hadoop源码

查看.....

(2)配置环境变量

1)将编译好的jar包复制到非中文的文件夹下

2)配置HADOOP_HOME环境变量

3)配置Path环境变量

%HADOOP_HOME%\bin

(3)工程搭建

1)创建Maven工程

2)修改pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hk.hdfs</groupId>
    <artifactId>hdfsClientDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <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.23.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>2.7.7</version>
        </dependency>
    </dependencies>
</project>

3)配置日志输出

在resource目录先创建log4j.properties文件

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n  
log4j.appender.logfile=org.apache.log4j.FileAppender  
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

4)创建测试类

public class HdfsClientTest {

    @Test
    public void hdfsTest1() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 配置在集群上运行
//        configuration.set("fs.defaultFS", "hdfs://hd01:9000");
//        FileSystem fileSystem = FileSystem.get(configuration);
        // 或者
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration);
        // 3.创建文件目录
        fs.mkdirs(new Path("/user/hkclient"));

        // 4.关闭资源
        fs.close();
    }
}

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

因为文件夹的权限问题,需要在运行时设置用户

-DHADOOP_USER_NAME=hdhk

5)测试

2、API操作

(1)创建目录

    @Test
    public void hdfsTest2() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 2.创建目录
        fs.mkdirs(new Path("/user/hkclient"));

        // 4.关闭资源
        fs.close();
    }}

(2)文件上传

    @Test
    public void hdfsTest1() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 设置副本数为2
        configuration.set("dfs.replication", "2");
        // 配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 2.上传文件
        fs.copyFromLocalFile(new Path("d:/hello.txt"), new Path("/user/hkclient/"));

        // 4.关闭资源
        fs.close();
    }

将hdfs-site.xml拷贝到项目的根目录下

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
    <!-- 指定HDFS副本的数量 -->
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>

结论:参数的优先级

        客户端代码中设置的值 >classpath下的用户自定义配置文件 >服务器的默认配置

(3)文件下载

    @Test
    public void hdfsTest4() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 2.配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 3.下载文件
        /**
         * 参数说明
         * 参数1:是否将原文件删除
         * 参数2:要下载的文件路径
         * 参数3:存放的位置
         * 参数4:是否开启文件校验
         */
        fs.copyToLocalFile(false, new Path("/user/hkclient/hello.txt"), new Path("d:/hello2.txt"), true);

        // 4.关闭资源
        fs.close();
    }

(4)文件名更改

    @Test
    public void hdfsTest5() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 2.配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 3.修改文件名称
        fs.rename(new Path("/user/hkclient/hello.txt"), new Path("/user/hkclient/hello2.txt"));

        // 4.关闭资源
        fs.close();
    }

(5)查看文件详情

    @Test
    public void hdfsTest6() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 2.配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 3.获取文件信息
        RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/user/hkclient"), true);
        while (files.hasNext()){
            LocatedFileStatus fileStatus = files.next();
            String pathName = fileStatus.getPath().getName();
            System.out.println("文件名称:" + pathName);

            long fileStatusLen = fileStatus.getLen();
            System.out.println("文件长度:" + fileStatusLen);

            FsPermission fsPermission = fileStatus.getPermission();
            System.out.println("文件权限:" + fsPermission);

            String group = fileStatus.getGroup();
            System.out.println("文件所属组:" + group);

            // 文件存储块信息
            BlockLocation[] locations = fileStatus.getBlockLocations();
            for (BlockLocation blockLocation : locations) {
                System.out.println("块长度:" + blockLocation.getLength());
                System.out.println("块偏移量:" + blockLocation.getOffset());
                for (String host : blockLocation.getHosts()) {
                    System.out.println("块存储节点主机名:" + host);
                }
            }
        }
        // 4.关闭资源
        fs.close();
    }

(6) 文件和文件夹判断

    @Test
    public void hdfsTest7() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 2.配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 3.获取文件列表
        FileStatus[] fileStatuses = fs.listStatus(new Path("/user/hkclient"));
        for (FileStatus fileStatus : fileStatuses) {
            if(fileStatus.isFile()){
                System.out.println("文件名称:" + fileStatus.getPath().getName());
            } else {
                System.out.println("文件夹 名称:" + fileStatus.getPath().getName());
            }
        }

        // 4.关闭资源
        fs.close();
    }

(7)文件夹删除

    @Test
    public void hdfsTest8() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        // 2.配置在集群上运行
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");
        // 3.删除文件夹
        fs.delete(new Path("/user/hkclient"), true);
        // 4.关闭资源
        fs.close();
    }

3、I/O流操作

        上面的API操作是HDFS框架封装好的,如果想自定义实现上述API的操作,可以采用IO流的方式实现数据的上传和下载。

(1)文件上传

    @Test
    public void test1() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");

        // 2.创建输入流
        FileInputStream inputStream = new FileInputStream(new File("d:/hello.txt"));
        // 3.获取输出流
        FSDataOutputStream outputStream = fs.create(new Path("/user/hkClient/hello2.txt"));
        // 4.流的对拷
        IOUtils.copyBytes(inputStream, outputStream, configuration);
        // 5.关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
        fs.close();
    }

(2)文件下载

    @Test
    public void test2() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");

        // 2.获取输入流
        FSDataInputStream inputStream = fs.open(new Path("/user/hkClient/hello2.txt"));
        // 3.创建输出流
        FileOutputStream outputStream = new FileOutputStream(new File("d:/hello_.txt"));
        // 4.流的对拷
        IOUtils.copyBytes(inputStream, outputStream, configuration);
        // 5.关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
        fs.close();
    }

(3)文件读取

        分块读取HDFS上的大文件,比如/hadoop-2.7.2.tar.gz

  • 获取第一块的数据
    @Test
    public void test3() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");

        // 2.获取输入流
        FSDataInputStream inputStream = fs.open(new Path("/user/hdhk/input/hadoop-2.7.7.tar.gz"));
        // 3.创建输出流
        FileOutputStream outputStream = new FileOutputStream(new File("d:/hadoop-2.7.7.tar.gz.p1"));
        // 4.流的对拷
        byte[] bytes = new byte[1024];
        for (int i = 0; i < 1024*128; i++) {
            inputStream.read(bytes);
            outputStream.write(bytes);
        }
        // 5.关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
        fs.close();
    }
  • 获取第二块的数据
    @Test
    public void test4() throws Exception{
        // 1.获取文件系统
        Configuration configuration = new Configuration();
        FileSystem fs = FileSystem.get(new URI("hdfs://hd01:9000"), configuration, "hdhk");

        // 2.获取输入流 定位数据
        FSDataInputStream inputStream = fs.open(new Path("/user/hdhk/input/hadoop-2.7.7.tar.gz"));
        inputStream.seek(1024*1024*128);
        // 3.创建输出流
        FileOutputStream outputStream = new FileOutputStream(new File("d:/hadoop-2.7.7.tar.gz.p2"));
        // 4.流的对拷
        IOUtils.copyBytes(inputStream, outputStream, configuration);
        // 5.关闭资源
        IOUtils.closeStream(inputStream);
        IOUtils.closeStream(outputStream);
        fs.close();
    }
  • 合并数据

在Window命令窗口中执行如下命令,对数据进行合并

type hadoop-2.7.7.tar.gz.p2 >> hadoop-2.7.7.tar.gz.p1

合并完成后,将hadoop-2.7.7.tar.gz.p1重新命名为hadoop-2.7.7.tar.gz。解压发现该tar包非常完整。

四、数据读写流程

1、数据写入

(1)写入流程

1)客户端通过Distributed FileSystem模块NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。

2)NameNode返回是否可以上传。

3)客户端请求第一个 Block上传到哪几个DataNode服务器上。

4)NameNode返回3个DataNode节点,分别为dn1dn2dn3

5)客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。

6)dn1dn2dn3逐级应答客户端。

7)客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2dn2传给dn3dn1每传一个packet会放入一个应答队列等待应答

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

(2)副本节点选择

1、第一个副本在client所处的节点上。如果客户端在集群外,随机选一个。

2、第二个副本和第一个副本位于相同机架,随机节点。

3、第三个副本位于不同机架,随机节点。

2、数据读取

1)客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址。

2)挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据

3)DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。

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

五、NameNode和SecondaryNameNode

1、NN与2NN工作机制

(1)由来

        如果NameNode中的元数据存储在NameNode节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,导致效率过低。因此,元数据需要存放在内存中。但是如果只存在内存中,一旦节点故障或断电,内存的元数据会丢失,整个集群就无法工作了因此需要磁盘中也备份元数据的FsImage。 这样又会带来新的问题,当内存中的元数据更新时,如果同时更新FsImage,就会导致节点更新效率过低,但如果不更新,就会发生一致性问题,一旦NameNode节点故障,就会产生数据丢失。因此,引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。这样,一旦NameNode节点故障,可以通过FsImage和Edits的合并,合成元数据。但是,如果一直往Edits中添加数据,会导致该文件数据过大,效率降低,而且一旦节点故障,恢复元数据需要的时间过长。因此,需要定期进行FsImage和Edits的合并,如果这个操作由NameNode节点完成,又会效率过低。因此,引入一个新的节点SecondaryNamenode,专门用于FsImage和Edits的合并。

(2)工作机制

1)首先nameNode工作

1)第一次启动namenode格式化后,创建fsimage和edits文件。如果不是第一次启动,直接加载编辑日志和镜像文件到内存。
2)客户端对元数据进行增删改的请求
3)namenode记录操作日志,更新滚动日志。
4)namenode在内存中对数据进行增删改

2)Secondary NameNode工作

1)Secondary NameNode询问namenode是否需要checkpoint。并带回namenode是否检查结果。
2)Secondary NameNode请求执行checkpoint。
3)namenode滚动正在写的edits日志
4)将滚动前的编辑日志和镜像文件拷贝到Secondary NameNode
5)Secondary NameNode加载编辑日志和镜像文件到内存,并合并。
6)生成新的镜像文件fsimage.chkpoint
7)拷贝fsimage.chkpoint到namenode
8)namenode将fsimage.chkpoint重新命名成fsimage

(3)工作机制详解

1、Fsimage:NameNode内存中元数据序列化后形成的文件。

2、Edits:记录客户端更新元数据信息的每一步操作(可通过Edits运算出元数据)。

3、NameNode启动时,先滚动Edits并生成一个空的edits.inprogress,然后加载Edits和Fsimage到内存中,此时NameNode内存就持有最新的元数据信息。Client开始对NameNode发送元数据的增删改的请求,这些请求的操作首先会被记录到edits.inprogress中(查询元数据的操作不会被记录在Edits中,因为查询操作不会更改元数据信息),如果此时NameNode挂掉,重启后会从Edits中读取元数据的信息。然后,NameNode会在内存中执行元数据的增删改的操作。

4、由于Edits中记录的操作会越来越多,Edits文件会越来越大,导致NameNode在启动加载Edits时会很慢,所以需要对Edits和Fsimage进行合并(所谓合并,就是将Edits和Fsimage加载到内存中,照着Edits中的操作一步步执行,最终形成新的Fsimage)。SecondaryNameNode的作用就是帮助NameNode进行Edits和Fsimage的合并工作。

5、SecondaryNameNode首先会询问NameNode是否需要CheckPoint(触发CheckPoint需要满足两个条件中的任意一个,定时时间到和Edits中数据写满了)。直接带回NameNode是否检查结果。SecondaryNameNode执行CheckPoint操作,首先会让NameNode滚动Edits并生成一个空的edits.inprogress,滚动Edits的目的是给Edits打个标记,以后所有新的操作都写入edits.inprogress,其他未合并的Edits和Fsimage会拷贝到SecondaryNameNode的本地,然后将拷贝的Edits和Fsimage加载到内存中进行合并,生成fsimage.chkpoint,然后将fsimage.chkpoint拷贝给NameNode,重命名为Fsimage后替换掉原来的Fsimage。NameNode在启动时就只需要加载之前未合并的Edits和Fsimage即可,因为合并过的Edits中的元数据信息已经被记录在Fsimage中。

2、Fsimage和Edits解析

(1)说明

hdfs namenode -format

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

fsimage_0000000000000000204
fsimage_0000000000000000204.md5
 seen_txid
VERSION

(1)Fsimage文件:HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的所有目录和文件idnode的序列化信息。 

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

(3)seen_txid文件保存的是一个数字,就是最后一个edits_的数字

(4)每次Namenode启动的时候都会将fsimage文件读入内存,并从00001开始到seen_txid中记录的数字依次执行每个edits里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成Namenode启动的时候就将fsimage和edits文件进行了合并。

(2)oiv查看Fsimage文件

oiv  apply the offline fsimage viewer to an fsimage
查看fsimage文件

1)基本语法

hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径

2)使用

案例: 查看fsimage_0000000000000000206文件

 hdfs oiv -p XML -i fsimage_0000000000000000206 -o /opt/module/hadoop-2.7.7/fsimage.xml

查看文件内容

<?xml version="1.0"?>
<fsimage>
    <NameSection>
        <genstampV1>1000</genstampV1>
        <genstampV2>1010</genstampV2>
        <genstampV1Limit>0</genstampV1Limit>
        <lastAllocatedBlockId>1073741833</lastAllocatedBlockId>
        <txid>206</txid>
    </NameSection>
    <INodeSection>
        <lastInodeId>16401</lastInodeId>
        <inode>
            <id>16385</id>
            <type>DIRECTORY</type>
            <name></name>
            <mtime>1769671677021</mtime>
            <permission>hdhk:supergroup:rwxr-xr-x</permission>
            <nsquota>9223372036854775807</nsquota>
            <dsquota>-1</dsquota>
        </inode>
        <inode>
            <id>16386</id>
            <type>DIRECTORY</type>
            <name>user</name>
            <mtime>1769827864416</mtime>
            <permission>hdhk:supergroup:rwxr-xr-x</permission>
            <nsquota>-1</nsquota>
            <dsquota>-1</dsquota>
        </inode>
    </INodeSection>
    <INodeReferenceSection></INodeReferenceSection>
    <SnapshotSection>
        <snapshotCounter>0</snapshotCounter>
    </SnapshotSection>
    <INodeDirectorySection>
        <directory>
            <parent>16385</parent>
            <inode>16386</inode>
        </directory>
    </INodeDirectorySection>
    <FileUnderConstructionSection></FileUnderConstructionSection>
    <SecretManagerSection>
        <currentId>0</currentId>
        <tokenSequenceNumber>0</tokenSequenceNumber>
    </SecretManagerSection>
    <CacheManagerSection>
        <nextDirectiveId>1</nextDirectiveId>
    </CacheManagerSection>
</fsimage>

 (3)oev查看Edits文件

oev   apply the offline edits viewer to an edits file
查看edits 文件

1)基本语法

hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径

2)使用

例如:查看edits_0000000000000000205-0000000000000000206文件

hdfs oev -p XML -i edits_0000000000000000205-0000000000000000206 -o /opt/module/hadoop-2.7.7/edits.xml

查看文件内容

<?xml version="1.0" encoding="UTF-8"?>
<EDITS>
  <EDITS_VERSION>-63</EDITS_VERSION>
  <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>90</TXID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>91</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16398</INODEID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1769825278361</MTIME>
      <ATIME>1769825278361</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME>DFSClient_NONMAPREDUCE_-1193472561_1</CLIENT_NAME>
      <CLIENT_MACHINE>192.168.10.39</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>hdhk</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <RPC_CLIENTID>1530358e-4c4a-4852-a29e-7a1641f4d691</RPC_CLIENTID>
      <RPC_CALLID>3</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>92</TXID>
      <BLOCK_ID>1073741831</BLOCK_ID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
    <DATA>
      <TXID>93</TXID>
      <GENSTAMPV2>1008</GENSTAMPV2>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD_BLOCK</OPCODE>
    <DATA>
      <TXID>94</TXID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <BLOCK>
        <BLOCK_ID>1073741831</BLOCK_ID>
        <NUM_BYTES>0</NUM_BYTES>
        <GENSTAMP>1008</GENSTAMP>
      </BLOCK>
      <RPC_CLIENTID></RPC_CLIENTID>
      <RPC_CALLID>-2</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_CLOSE</OPCODE>
    <DATA>
      <TXID>95</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1769825278571</MTIME>
      <ATIME>1769825278361</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME></CLIENT_NAME>
      <CLIENT_MACHINE></CLIENT_MACHINE>
      <OVERWRITE>false</OVERWRITE>
      <BLOCK>
        <BLOCK_ID>1073741831</BLOCK_ID>
        <NUM_BYTES>34</NUM_BYTES>
        <GENSTAMP>1008</GENSTAMP>
      </BLOCK>
      <PERMISSION_STATUS>
        <USERNAME>hdhk</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD</OPCODE>
    <DATA>
      <TXID>96</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>16399</INODEID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <REPLICATION>2</REPLICATION>
      <MTIME>1769825422102</MTIME>
      <ATIME>1769825422102</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME>DFSClient_NONMAPREDUCE_-1704095899_1</CLIENT_NAME>
      <CLIENT_MACHINE>192.168.10.39</CLIENT_MACHINE>
      <OVERWRITE>true</OVERWRITE>
      <PERMISSION_STATUS>
        <USERNAME>hdhk</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
      <RPC_CLIENTID>87367ae5-fc0e-4134-abca-002dd56b764e</RPC_CLIENTID>
      <RPC_CALLID>4</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ALLOCATE_BLOCK_ID</OPCODE>
    <DATA>
      <TXID>97</TXID>
      <BLOCK_ID>1073741832</BLOCK_ID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_SET_GENSTAMP_V2</OPCODE>
    <DATA>
      <TXID>98</TXID>
      <GENSTAMPV2>1009</GENSTAMPV2>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_ADD_BLOCK</OPCODE>
    <DATA>
      <TXID>99</TXID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <BLOCK>
        <BLOCK_ID>1073741832</BLOCK_ID>
        <NUM_BYTES>0</NUM_BYTES>
        <GENSTAMP>1009</GENSTAMP>
      </BLOCK>
      <RPC_CLIENTID></RPC_CLIENTID>
      <RPC_CALLID>-2</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_CLOSE</OPCODE>
    <DATA>
      <TXID>100</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/user/hkclient/hello.txt</PATH>
      <REPLICATION>2</REPLICATION>
      <MTIME>1769825422279</MTIME>
      <ATIME>1769825422102</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME></CLIENT_NAME>
      <CLIENT_MACHINE></CLIENT_MACHINE>
      <OVERWRITE>false</OVERWRITE>
      <BLOCK>
        <BLOCK_ID>1073741832</BLOCK_ID>
        <NUM_BYTES>34</NUM_BYTES>
        <GENSTAMP>1009</GENSTAMP>
      </BLOCK>
      <PERMISSION_STATUS>
        <USERNAME>hdhk</USERNAME>
        <GROUPNAME>supergroup</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_RENAME_OLD</OPCODE>
    <DATA>
      <TXID>101</TXID>
      <LENGTH>0</LENGTH>
      <SRC>/user/hkclient/hello.txt</SRC>
      <DST>/user/hkclient/hello2.txt</DST>
      <TIMESTAMP>1769826456682</TIMESTAMP>
      <RPC_CLIENTID>609371d1-f626-4d69-b257-35ca61a0545a</RPC_CLIENTID>
      <RPC_CALLID>0</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_DELETE</OPCODE>
    <DATA>
      <TXID>102</TXID>
      <LENGTH>0</LENGTH>
      <PATH>/user/hkclient</PATH>
      <TIMESTAMP>1769827258219</TIMESTAMP>
      <RPC_CLIENTID>64c1da59-7598-4879-9c7e-f7b9efc9c9d3</RPC_CLIENTID>
      <RPC_CALLID>0</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_END_LOG_SEGMENT</OPCODE>
    <DATA>
      <TXID>103</TXID>
    </DATA>
  </RECORD>
</EDITS>

3、 chkpoint时间设置

修改 hdfs-default.xml 文件

(1)SecondaryNameNode每隔一小时执行一次

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

(2)一分钟检查一次操作次数,当操作次数达到1百万时,SecondaryNameNode执行一次。

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

4、NameNode故障处理

(1)方式一

        将SecondaryNameNode中数据拷贝到namenode存储数据的目录;

模拟故障具体操作:

1、关闭nameNode

kill -9 namenode进程

2、删除namenode存储的数据

sudo rm -rf /opt/module/hadoop-2.7.7/data/tmp/dfs/name/*

3、拷贝SecondaryNameNode数据到原namenode存储数据目录

scp -r hdhk@hd03:/opt/module/hadoop-2.7.7/data/tmp/dfs/namesecondary/* /opt/module/hadoop-2.7.7/data/tmp/dfs/name/

4、重新启动NameNode

 hadoop-daemon.sh start namenode

(2)方式二

        使用 -importCheckpoint 选项启动NameNode守护进程,从而将SecondaryNameNode中数据拷贝到NameNode目录

故障模拟:

1、关闭hdfs-site.xml文件

<property>

  <name>dfs.namenode.checkpoint.period</name>

  <value>120</value>

</property>

<property>

  <name>dfs.namenode.name.dir</name>

  <value>/opt/module/hadoop-2.7.7/data/tmp/dfs/name</value>

</property>

2、关闭nameNode

kill -9 namenode进程

2、删除namenode存储的数据

sudo rm -rf /opt/module/hadoop-2.7.7/data/tmp/dfs/name/*

3、如果SecondaryNameNode不和Namenode一个主机节点上,需要将SecondaryNameNode存储数据的目录拷贝到Namenode存储数据的平级目录并删除in_use.lock文件

scp -r hdhk@hd03:/opt/module/hadoop-2.7.7/data/tmp/dfs/namesecondary /opt/module/hadoop-2.7.7/data/tmp/dfs/

4、导入检查点数据(等待一会ctrl+c结束掉)

hdfs namenode -importCheckpoint

5、重新启动NameNode

 hadoop-daemon.sh start namenode

5、集群安全模式

(1)概述

1)nameNode启动

        首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各项操作。一旦在内存中成功建立文件系统元数据的映像,则创建一个新的fsimage文件和一个空的编辑日志。此时,namenode开始监听datanode请求。但是此刻,namenode运行在安全模式,即namenode的文件系统对于客户端来说是只读的。

2)DataNode启动

        系统中的数据块的位置并不是由namenode维护的,而是以块列表的形式存储在datanode中。在系统的正常操作期间,namenode会在内存中保留所有块位置的映射信息。在安全模式下,各个datanode会向namenode发送最新的块列表信息,namenode了解到足够多的块位置信息之后,即可高效运行文件系统。

3)安全模式退出判断

        如果满足“最小复本条件”,namenode会在30秒之后就退出安全模式。所谓的最小复本条件指的是在整个文件系统中99.9%的块满足最小复本级别(默认值:dfs.replication.min=1)。在启动一个刚刚格式化的HDFS集群时,因为系统中还没有任何块,所以namenode不会进入安全模式。

(2)基本语法

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

查看安全模式状态:

hdfs dfsadmin -safemode get

进入安全模式状态

hdfs dfsadmin -safemode enter

等待安全模式状态

hdfs dfsadmin -safemode wait

编写一个执行脚本safemode.sh

#!/bin/bash
hdfs dfsadmin -safemode wait
hdfs dfs -put /opt/module/hadoop-2.7.7/README.txt /user/hkclient/

修改脚本的执行权限        chmod 777 safemode.sh

执行脚本        ./safemode.sh

窗体进入等待撞他,此时文件并没有写入进去

离开安全模式状态

hdfs dfsadmin -safemode leave

再开启一个窗口执行离开命令

再次查看第一个窗口,发现已经执行完毕,文件写入成功

6、NameNode多目录配置

nameNode的本地目录可以配置成多个,且每个目录存放内容相同,增加了可靠性。

具体配置:

(1)修改hdfs-site.xml文件

<property>
        <name>dfs.namenode.name.dir</name>
        <value>file:///${hadoop.tmp.dir}/dfs/name1,file:///${hadoop.tmp.dir}/dfs/name2</value>
</property>

(2)停止集群,删除data和logs中所有数据。

stop-dfs.sh

stop-yarn.sh

rm -rf data/ logs/

(3)格式化集群并启动

hdfs namenode –format
start-dfs.sh

六、DataNode

1、工作机制

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

2、数据完整性

1)当DataNode读取block的时候,它会计算checksum。
2)如果计算后的checksum,与block创建时值不一样,说明block已经损坏。
3)client读取其他DataNode上的block。
4)datanode在其文件创建后周期验证checksum。

3、掉线时限参数设置

        datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。

如果定义超时时间为timeout,则超时时长的计算公式为:

timeout  = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。

而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。

        需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。

<property>

    <name>dfs.namenode.heartbeat.recheck-interval</name>

    <value>300000</value>

</property>

<property>

    <name> dfs.heartbeat.interval </name>

    <value>3</value>

</property>

4、服役新数据节点

在原有集群基础上动态添加新的数据节点。

(1)准备工作

1)克隆一台虚拟机

        以hd01虚拟机克隆出hd04虚拟机

2)修改ip地址和主机名称

        修改IP为192.168.10.224,主机名为hd04

3)修改xsync文件,增加新增节点的同步ssh

4)删除原来HDFS文件系统留存的文件

rm -rf /opt/module/hadoop-2.7.7/data

5)source一下配置文件

source /etc/profile

(2)具体操作

1)在namenode的/opt/module/hadoop-2.7.7/etc/hadoop目录下创建dfs.hosts文件

vi dfs.hosts

hd01
hd02

hd03

hd04

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

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

3)刷新namenode

hdfs dfsadmin -refreshNodes

4)更新resourcemanager节点

 yarn rmadmin -refreshNodes

5)在namenode的slaves文件中增加新主机名称

增加04不需要分发

hd01
hd02

hd03

hd04

6)单独命令启动新的数据节点和节点管理器

hadoop-daemon.sh start datanode
yarn-daemon.sh start nodemanager

7)在web浏览器上检查是否ok

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

 ./start-balancer.sh

5、退役数据节点

        添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。添加到白名单的主机节点,都允许访问NameNode,不在白名单的主机节点,都会被退出。

(1)添加白名单

1)在namenode的/opt/module/hadoop-2.7.7/etc/hadoop目录下创dfs.hosts文件

touch dfs.hosts
vim dfs.hosts

添加如下主机名称(需要的节点)

hd01
hd02

hd03

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

<property>

        <name>dfs.hosts</name>

        <value>/opt/module/hadoop-2.7.7/etc/hadoop/dfs.hosts</value>

</property>

3)配置文件分发

xsync hdfs-site.xml

4)刷新namenode、刷新resourcemanager

hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes

5)在web浏览器上查看

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

./start-balancer.sh

(2)黑名单退役

1)在namenode的/opt/module/hadoop-2.7.7/etc/hadoop目录下创建dfs.hosts.exclude文件

touch dfs.hosts.exclude
vim dfs.hosts.exclude
 

添加如下主机名称(要退役的节点)
hd04

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

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

3)刷新namenode、刷新resourcemanager

hdfs dfsadmin -refreshNodes
yarn rmadmin -refreshNodes

4)查看Web浏览器,退役节点的状态为decommission in progress(退役中),说明数据节点正在复制块到其他节点,

5)等待退役节点状态为decommissioned(所有块已经复制完成),停止该节点及节点资源管理器。注意:如果副本数是3,服役的节点小于等于3,是不能退役成功的,需要修改副本数后才能退役

hadoop-daemon.sh stop datanode

yarn-daemon.sh stop nodemanager

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

./start-balancer.sh

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

6、Datanode多目录配置

datanode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本。

修改hdfs-site.xml

<property>
        <name>dfs.datanode.data.dir</name>
        <value>file:///${hadoop.tmp.dir}/dfs/data1,file:///${hadoop.tmp.dir}/dfs/data2</value>
</property>

七、HDFS 2.X新特性

1、集群间数据拷贝

(1)主机之间的数据拷贝

推 push:

        scp –r hello.txt root@hd02:/user/hdhk/hello.txt
拉 pull 

        scp –r root@hd02:/user/hdhk/hello.txt hello.txt       

通过本地主机中转实现两个远程主机的文件复制;如果在两个远程主机之间ssh没有配置的情况下可以使用该方式。
        scp –r root@hd03:/user/hdhk/hello.txt root@hd02:/user/hdhk        

(2)hadoop集群之间的递归数据复制

hadoop distcp hdfs://hd02:9000/user/hdhk/hello.txt   hdfs://hd03:9000/user/hdhk/hello.txt

2、小文件存档

(1)存储小文件的弊端

        每个文件均按块存储,每个块的元数据存储在namenode的内存中,因此hadoop存储小文件会非常低效。因为大量的小文件会耗尽namenode中的大部分内存。但注意,存储小文件所需要的磁盘容量和存储这些文件原始内容所需要的磁盘空间相比也不会增多。例如,一个1MB的文件以大小为128MB的块存储,使用的是1MB的磁盘空间,而不是128MB。

(2)解决方案

        Hadoop存档文件或HAR文件,是一个更高效的文件存档工具,它将文件存入HDFS块,在减少namenode内存使用的同时,允许对文件进行透明的访问。具体说来,Hadoop存档文件对内还是一个一个独立文件,对namenode而言却是一个整体,减少了namenode的内存。

(3)步骤

1)启动YARN进程

start-yarn.sh

2)归档文件

        把/user/hdhk目录里面的所有文件归档成一个叫mygd.har的归档文件,并把归档后文件存储到/user/myFile路径下。

hadoop archive -archiveName mygd.har -p /user/hdhk  /user/myFile

3)查看归档

hadoop fs -lsr /user/myFile/mygd.har

hadoop fs -lsr har:///user/myFile/mygd.har

4)归档文件

hadoop fs -cp har:///user/myFile/mygd.har /* /user/hdhk

3、回收站

        开启回收站功能,可以将删除的文件在不超时的情况下,恢复原数据,起到防止误删除、备份等作用。

(1)工作机制

默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间。

默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间。如果该值为0,则该值设置和fs.trash.interval的参数值相等。

要求fs.trash.checkpoint.interval<=fs.trash.interval。

(2)启用回收站

修改core-site.xml文件,配置垃圾回收时间为1分钟

<property>

    <name>fs.trash.interval</name>

    <value>1</value>

</property>

(3)查看回收站

回收站在集群中的的路径:

/user/hdhk/.Trash/….

(4)修改访问垃圾回收站用户名称

进入垃圾回收站用户名称,默认是dr.who,修改为hdhk用户,修改core-site.xml文件

<property>

  <name>hadoop.http.staticuser.user</name>

  <value>hdhk</value>

</property>

(5)通过程序删除的文件不会经过回收站,需要调用moveToTrash()才进入回收站

Trash trash = New Trash(conf);
trash.moveToTrash(path);

(6)恢复回收站数据

hadoop fs -mv /user/hdhk/.Trash/Current/user/hdhk/input    /user/hdhk/input

(7)清空回收站

hadoop fs -expunge

4、快照管理

        快照相当于对目录做一个备份。并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。

(1)基本语法

开启指定目录的快照功能

hdfs dfsadmin -allowSnapshot 路径

禁用指定目录的快照功能,默认是禁用

hdfs dfsadmin -disallowSnapshot 路径

对目录创建快照

hdfs dfs -createSnapshot 路径

指定名称创建快照

hdfs dfs -createSnapshot 路径 名称

重命名快照

hdfs dfs -renameSnapshot 路径 旧名称 新名称

列出当前用户所有可快照目录

hdfs lsSnapshottableDir

比较两个快照目录的不同之处

hdfs snapshotDiff 路径1 路径2 

删除快照

hdfs dfs -deleteSnapshot <path> <snapshotName>

更多推荐