HDFS的简单介绍和应用

hdfs应用

1. hdfs概述

1.1 产生背景

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

1.2 什么是hdfs

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

1.3 hdfs优点

  • 高容错性

    高容错性

  • 适合处理大数据

    • 数据规模:能够处理数据规模达到GB、TB、甚至PB级别的数据;
    • 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
  • 可构建在廉价机器上,通过多副本机制,提高可靠性

1.4 hdfs缺点

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

2. hdfs架构

2.1 hdfs架构

hdfs架构图

2.2 Namenode节点

  • ​ NameNode(nn):就是Master,它是一个主管、管理者。
    • (1)管理HDFS的名称空间;
    • (2)配置副本策略;
    • (3)管理数据块(Block)映射信息;
    • (4)处理客户端读写请求。

2.3 datanode节点

  • ​ DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
    • (1)存储实际的数据块;
    • (2)执行数据块的读/写操作。

2.4 客户端

  • (1)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
  • (2)与NameNode交互,获取文件的位置信息;
  • (3)与DataNode交互,读取或者写入数据;
  • (4)Client提供一些命令来管理HDFS,比如NameNode格式化;
  • (5)Client可以通过一些命令来访问HDFS,比如对HDFS增删查改操作;

2.5 Secondary NameNode

  • ​ Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
  • (1)辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NameNode ;
  • (2)在紧急情况下,可辅助恢复NameNode。

2.6 Fsimage和Edits是什么

fsimage:HDFS文件系统元数据的镜像文件,其中包含HDFS文件系统的所有目录和文件inode及相关属性的序列化信息。

edits:用户操作的编辑日志文件,存放HDFS文件系统的所有更新操作的动作,文件所有写操作会被记录到Edits文件中。

在namenode运行期间, 客户端对hdfs的写操作都保存到edit文件中, 久而久之就会造成edit文件变得很大, 如果namenode重启, 它会将fsimage中的内容映射到内存中, 然后再一条一条执行edit文件中的操作, 所以日志文件太大会导致重启速度很慢。所以在namenode运行的时候就要将edit logs和fsimage定期合并。

3. 数据块

  • HDFS中的文件在物理上是分块存储(Block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在Hadoop2.x版本中是128M,老版本中是64M。

4. HDFS的Shell操作

4.1 基本语法

  • hadoop fs 具体命令 OR hdfs dfs 具体命令,两个是完全相同的。

4.2 命令大全

[hadoop@hadoop-001 hadoop-3.1.3]$ bin/hadoop fs

[-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] <localsrc> ... <dst>]
        [-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-count [-q] <path> ...]
        [-cp [-f] [-p] <src> ... <dst>]
        [-createSnapshot <snapshotDir> [<snapshotName>]]
        [-deleteSnapshot <snapshotDir> <snapshotName>]
        [-df [-h] [<path> ...]]
        [-du [-s] [-h] <path> ...]
        [-expunge]
        [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
        [-getfacl [-R] <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] <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>]]
        [-setrep [-R] [-w] <rep> <path> ...]
        [-stat [format] <path> ...]
        [-tail [-f] <file>]
        [-test -[defsz] <path>]
        [-text [-ignoreCrc] <src> ...]
        [-touchz <path> ...]
        [-usage [cmd ...]]

4.3 HDFS直接操作

1)-ls: 显示目录信息

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -ls /

2)-mkdir:在HDFS上创建目录

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -mkdir -p /sanguo/shuguo

3)-cat:显示文件内容

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -cat /sanguo/shuguo/kongming.txt

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

指令中的a、b、c分别表示一个数字,其中a对应文件所有者权限,b对应文件所有者所在组权限,c对应其他身份权限。

对于a、b、c各自来讲,它们都是0~7的数字,对应r、w、x三个二进制位按序组成的二进制数,举个例子,如果是只可读,对应的二进制数就是“100”,也就是4;如果是可读可写不可执行,那么对应二进制数为“110”,也就是6。

666表示所有用户可读可写。

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -chmod 666 /sanguo/shuguo/kongming.txt
[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -chown hadoop:hadoop  /sanguo/shuguo/kongming.txt

5)-cp :从HDFS的一个路径拷贝到HDFS的另一个路径

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt

6)-mv:在HDFS目录中移动文件

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -mv /zhuge.txt /sanguo/shuguo/

7)-tail:显示一个文件的末尾1kb的数据

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -tail /sanguo/shuguo/kongming.txt

8)-rm:删除文件或文件夹

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -rm /user/hadoop/test/jinlian2.txt

9)-rmdir:删除空目录

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -mkdir /test
[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -rmdir /test

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

  • -h按照适合阅读的形式人性化显示文件大小
[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -du -h /user/hadoop/test
1.3 K /user/hadoop/test/README.txt
1.4 K /user/hadoop/test/zaiyiqi.txt
  • -s 查看指定文件夹大小信息
[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -du -s -h /user/hadoop/test
2.7 K /user/hadoop/test

11)-setrep:设置HDFS中文件的副本数量

[hadoop@hadoop-001 hadoop-3.1.3]$ hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt
这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。

5. HDFS客户端操作

5.1 准备Windows关于Hadoop的开发环境

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

选择Hadoop-3.1.0,拷贝到其他地方(比如d:)。

2)配置HADOOP_HOME环境变量。

3)配置Path环境变量

5.2 创建maven工程

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

<?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.gec</groupId>
    <artifactId>HdfsClientDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>


    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.12.0</version>
        </dependency>


        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>3.1.3</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

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

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
    <Appenders>
        <!-- 类型名为Console,名称为必须属性 -->
        <Appender type="Console" name="STDOUT">
            <!-- 布局为PatternLayout的方式,
            输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
            <Layout type="PatternLayout"
                    pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
        </Appender>

    </Appenders>

    <Loggers>
        <!-- 可加性为false -->
        <Logger name="test" level="info" additivity="false">
            <AppenderRef ref="STDOUT" />
        </Logger>

        <!-- root loggerConfig设置 -->
        <Root level="info">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>
</Configuration>

5.3 创建HdfsClient类

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

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

5.4 运行时需要配置用户名称

运行时需要配置用户名称

客户端去操作HDFS时,是有一个用户身份的。默认情况下,HDFS客户端API会从JVM中获取一个参数来作为自己的用户身份:-DHADOOP_USER_NAME=hadoop,hadoop为用户名称。

5.5 HDFS文件上传(测试参数优先级)

  • 编写源代码

    @Test
        public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {
    
            // 1 获取文件系统
            Configuration configuration = new Configuration();
            //configuration.set("dfs.replication", "2");
            FileSystem fs = FileSystem.get(new URI("hdfs://hadoop-001:9820"), configuration, "hadoop");
    
            // 2 上传文件
            fs.copyFromLocalFile(new Path("D:/wc/wc.txt"), new Path("/wc.txt"));
    
            // 3 关闭资源
            fs.close();
    
            System.out.println("over");
    
        }
    

5.6 HDFS文件下载

  • 编写源代码

      @Test
        public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{
    
            // 1 获取文件系统
            Configuration configuration = new Configuration();
            FileSystem fs = FileSystem.get(new URI("hdfs://hadoop-001:9820"), configuration, "hadoop");
    
            // 2 执行下载操作
            // boolean delSrc 指是否将原文件删除
            // Path src 指要下载的文件路径
            // Path dst 指将文件下载到的路径
            // boolean useRawLocalFileSystem 是否开启文件校验
            fs.copyToLocalFile(false, new Path("/wc.txt"), new Path("d:/wc/wc.txt"), true);
    
            // 3 关闭资源
            fs.close();
        }
    

5.7 HDFS删除文件和目录

  • 编写源代码

     @Test
        public void testDelete() throws IOException, InterruptedException, URISyntaxException{
    
            // 1 获取文件系统
            Configuration configuration = new Configuration();
            FileSystem fs = FileSystem.get(new URI("hdfs://hadoop-001:9820"), configuration, "hadoop");
    
            // 2 执行删除
            fs.delete(new Path("/1108/"), true);
    
            // 3 关闭资源
            fs.close();
        }
    

6. HDFS写数据流程

HDFS写数据流程
(1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。

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

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

(4)NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。

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

(6)dn1、dn2、dn3逐级应答客户端。

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

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

7. HDFS读数据流程

HDFS读数据流程

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

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

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

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

posted @ 2022-11-12 22:02  MrSponge  Views(645)  Comments(0Edit  收藏  举报