HDFS


HDFS产出背景及定义

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

HDFS是一个文件系统,用于存储文件,通过目录来定位文件。其次是分布式的,由很多台服务器联合起来实现功能,集群中的服务器有各自的角色。

HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘。

优缺点

  • 优点
    • 高容错性,数据自动保存多个副本,是通过增加副本形式,提高容错性。某一个副本丢失时候,会自动恢复
    • 适合处理大数据,能够存取大规模的数据。存取大规模的文件,可在廉价的机器上通过多个副本机制,提高可靠性
  • 缺点
    • 不适合低延时的数据访问,比如毫秒级别的存储数据,是做不到的
    • 无法高效的对大量小文件进行存储
    • 不支持并发写入,文件随机修改

HDFS的Shell操作

bin/hadoop fs 具体命令   OR  bin/hdfs dfs 具体命令两个是完全相同的

从本地文件上传到HDFS的命令

  • put,复制
    • hadoop fs -put NOTICE.txt / 
  • copyFromLocal,和put基本一样,多了一个多线程拷贝的功能
    • hadoop fs -copyFromLocal README.txt / 
  • moveFromLocal,剪切
    • hadoop fs -moveFromLocal README.txt / 
  • appendToFile,追加一个文件到另一个文件
    • hadoop fs -appendToFile NOTICE.txt /README.txt 将NOTICE.txt追加到根目录下的README.txt

从HDFS到本地

  • get,下载
    • hadoop fs -get /README.txt . ,下载到当前目录
  • getmerge,合并下载,可以批量下载文件
    • hadoop fs -getmerge /*.txt 1.txt 将hdfs根目录下的所有文件,下载到1.txt中
  • copyToLocal,也是下载,和get完全一样

HDFS客户端操作

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

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

在项目的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>

创建测试类

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
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;
import java.util.Arrays;
/**
 * @author fangxi created by 2020/9/6
 */
public class HdfsTest {
    private FileSystem fileSystem;
    @Before
    public void create() throws IOException, InterruptedException {
        this.fileSystem = FileSystem.get(URI.create("hdfs://10.211.55.40:8020"), new Configuration(), "fangxi");
    }
    @After
    public void close() throws IOException {
        this.fileSystem.close();
    }
    /**
     * 上传
     * @throws IOException
     */
    @Test
    public void upload() throws IOException {
        Path src = new Path("/Users/fangxi/Java/workspace/bigdata/hdfs01/src/test/java/com/storyhasyou/hdfs/HdfsTest.java");
        // 第一个参数是否删除源文件,第二个是源文件地址,第三个目标地址
        fileSystem.copyFromLocalFile(false, src, new Path("/"));
    }
    /**
     * 下载
     * @throws IOException
     */
    @Test
    public void download() throws IOException {
        fileSystem.copyToLocalFile(new Path("/README.txt"), new Path("/Users/fangxi/Java/workspace/bigdata/hdfs01"));
    }
    /**
     * 追加
     */
    @Test
    public void append() throws IOException {
        FSDataOutputStream outputStream = fileSystem.append(new Path("/README.txt"));
        outputStream.write("www.storyhasyou.top".getBytes());
        IOUtils.closeStream(fileSystem);
    }
    /**
     * 查看文件或文件夹
     * @throws IOException
     */
    @Test
    public void ls() throws IOException {
        FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
        Arrays.stream(fileStatuses).forEach(System.out::println);
    }
    /**
     * 移动或者重命名
     * @throws IOException
     */
    @Test
    public void mv() throws IOException {
        fileSystem.rename(new Path("/README.txt"), new Path("/abc.txt"));
    }
}

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

HDFS读数据流程

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


Author: Re:0
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source Re:0 !
 Previous
Disruptor-高性能队列 Disruptor-高性能队列
Disruptor是什么?官网介绍:https://github.com/LMAX-Exchange/disruptor/wiki(https://github.com/LMAX-Exchange/disruptor/wiki)
2022-11-17
Next 
Hadoop集群搭建 Hadoop集群搭建
准备三台虚拟机(hadoop01, hadoop02, hadoop03),虚拟机配置要求,单台虚拟机:内存4G,硬盘50G。要求三台机器可以免密登陆三台机器的规划
2022-09-06
  TOC