淘先锋技术网

首页 1 2 3 4 5 6 7

HDFS概述

为什么会有HDFS

随着时间的积累,数据量会越来越大,一台服务器保存不完,那就保存在多台服务器下,多台服务器之间不便于管理,所以需要分布式文件管理系统来管理多台服务器上的文件。HDFS就是分布式文件管理系统的一种。

HDFS是什么

HDFS是一个分布式文件管理系统,用于存储文件,通过目录树来定位文件位置。

HDFS使用场景

适合一次写入,多次读出的场景。一个文件从创建到写入到关闭之后不需要改变

HDFS优缺点

优点:

​ 1)高容错性

​ 数据会自动保存多个副本,某一个副本丢失了,会自动恢复

​ 2)适合大数据处理

​ 可以处理GB、TB甚至是PB的数据规模

​ 能够处理上百万个文件,数量非常大

​ 3)可以构造在配置较低的服务器上,通过多副本机制,提高容错性

缺点:

​ 1)不适合处理低延时数据访问,像毫秒级的数据存储,是无法实现的

​ 2)无法对大量的小文件进行存储

​ 1、存储大量小文件,会占用大量的NameNode的内存存储目录和信息,但NameNode的内存是有限的

​ 2、存储大量小文件,会增加寻址时间

​ 3)不支持并发写、修改文件

​ 1、一个文件只能有一个写,不允许有多个线程读

​ 2、仅支持数据追加,不支持修改文件

HDFS的组成架构

在这里插入图片描述

NameNode:就是一个管理者

1、管理HDFS的名称空间

2、配置副本策略

3、管理数据块的映射信息

4、处理客户端读写请求

DataNode执行实际的操作

1、存储实际的块大小

2、执行数据块的读写操作

Client就是客户端

1、文件切片,上传文件的时候,Client将文件切成一个一个的Block,然后才进行上传

2、与NameNode交互,获取文件位置信息

3、与DataNode交互,读取或写入信息

4、Client提供一些命令来管理HDFS

5、Client可以通过命令来访问HDFS

Secondary NameNode :当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务

1、辅助NameNode,分担工作量

2、在紧急情况下,可辅助恢复NameNode

HDFS文件块大小

HDFS中的文件是分块存储的(block),块大小可以通过配置参数来规定(dfs.blocksize),默认大小1.X版本为64M,2.X和3.X版本为128M

为什么块不能设置过大,也不能设置过小

1、HDFS的块设置太小,会增加寻址时间,程序一直在找块开始的位置

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

总结

1、HDFS块的大小设置主要取决于磁盘的传输效率

2、寻址时间为传输时间的1%最佳

常用命令

hadoop fs 具体命令

上传:

-moveFormLocal :从本地剪切到HDFS

-copyFromLocal:从本地拷贝文件到HDFS路径中去

-put:等同于-copyFromLocal

-appendToFile:追加到文件末尾

下载:

-copyToLocal:从HDFS拷贝到本地

-get:等同于copyToLocal

直接操作:

-ls:显示目录信息

-cat:显示文件内容

-chgrp、-chmod、-chown:修改文件所属权限

-mkdir:创建路径

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

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

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

-rm:删除文件或文件夹

-rm -r:递归删除目录及目录里面内容

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

[root@node00 hadoop-3.1.3]# hadoop fs -du -s -h /input
[root@node00 hadoop-3.1.3]# hadoop fs -du -h/input

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

设置副本数量属于动态设置,三台机器,设置了5个副本,但实际上只有3个副本

API

环境准备

Hadoop3.1.2安装包

链接:https://pan.baidu.com/s/1Kbn5uOKFJ8G8BHMBKlnn1Q
提取码:0000 在这里插入图片描述

1、配置Windows的环境
在这里插入图片描述

点击winutils,没有反应就说明安装好了

2、改pom.xml

  <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>3.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.30</version>
        </dependency>
    </dependencies>

3、resources目录下创建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
操作HDFS
package com;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class myzHdfsClient {

    private FileSystem fs;

    @Before
    public void before() throws URISyntaxException, IOException, InterruptedException {
        URI uri = new URI("hdfs://node00:8020");
        Configuration entries = new Configuration();
        fs = FileSystem.get(uri, entries,"root");
    }

    @After
    public void after() throws IOException {
        fs.close();
    }

    //创建目录
    @Test
    public void clientMkdir() throws URISyntaxException, IOException, InterruptedException {

        fs.mkdirs(new Path("/xiyouji/huaguoshan"));

    }

    //上传文件
    @Test
    public void put() throws IOException {
        fs.copyFromLocalFile(true,true,new Path("D:\\wukong.txt"),new Path("hdfs://node00/xiyouji/huaguoshan"));
    }

}

剩下的删除 移动,自己看方法名慢慢试

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(先从磁盘读取数据放到奔到内存缓存)。以Pakcet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3,dn1每传一个packet会放入一个应答队列等待应答

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

HDFS写数据的过程中,NameNode会选择距离待上传数据距离最近的DataNode接收数据。

节点距离: 两个节点到达最近的共同祖先的距离总和

HDFS读取流程

在这里插入图片描述

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

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

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

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

副本节点选择

在这里插入图片描述

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

2、第二个副本在另一台机架,随机一个节点

3、第三个副本在第二个副本节点所在的机架

nn和2nn工作机制

在这里插入图片描述

一阶段:NameNode工作

1、第一次启动NameNode格式化后,创建Fsimage和Edits文件,如果不是第一次启动,直接加载编辑日志和镜像文件到内存

2、客户端对元数据进行增删改的请求

3、NameNode记录操作日志,更新滚动日志

4、NameNode在内存中对元数据进行增删改

二阶段.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

Fsimage 和 Edits

NameNode格式化之后,会在/usr/local/hadoop-3.1.3/data/tmp/dfs/name/current目录中产生文件

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

2、Edits文件:存放HDFS文件系统的所有更新的路径,文件系统客户端执行的所有有写操作都会被记录到文件

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

4、每次NameNode启动的时候都会将Fsimage文件读入内存,加载Edits里面的更新操作,保证内存中的数据时最新的。

查看Fsimage 文件

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

[root@node00 current]$ hdfs oiv -p XML -i fsimage_0000000000000000028 -o /usr/local/hadoop-3.1.3/fsimage.xml

在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。

查看Edits 文件

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

[root@node00 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000015 -o /usr/local/hadoop-3.1.3/edits.xml

CheckPoint时间设置

一般2nn隔一个小时就执行一次

一分钟检查一次操作次数,当操作次数达到一百万的时候,2nn执行一次

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>60s</value>
<description> 1 分钟检查一次操作次数</description>
</property>

DataNode

DataNode工作机制

在这里插入图片描述

1、DataNode向NameNode注册

2、注册成功6个小时向NameNode上报所有块信息

3、3秒发送一次心跳,心跳返回结果带有命令。

4、超过10分钟没有收到心跳,就会认为该节点不可用

数据损坏

DataNode节点上的数据损坏了怎么办

无非就是读取时采用校验,判断数据是否损,如果损坏就去读取别的节点

1、当DataNode读取 Block 的时候,它会计算CheckSum。

2、如计算后的CheckSum,与 Block 创建时值不一样,说明Block已经损坏。

3、读取别的节点上的Block

常用的校验算法:crc(32) md5(128) shal(160)

DataNode 掉线

1、DataNode掉线,或者网络波动,总之就是无法和NameNode进行通信

2、NameNode不会立即认为它挂了,要经过一段时间(超时时间)

3、HDFS默认超时时间10分钟+30秒

hdfs-site.xml

<!--参数为毫秒-->
<property>
 <name>dfs.namenode.heartbeat.recheck-interval</name>
 <value>300000</value>
</property>
<!--参数为秒-->
<property>
 <name>dfs.heartbeat.interval</name>
 <value>3</value>
</property>

候,它会计算CheckSum。

2、如计算后的CheckSum,与 Block 创建时值不一样,说明Block已经损坏。

3、读取别的节点上的Block

常用的校验算法:crc(32) md5(128) shal(160)

DataNode 掉线

1、DataNode掉线,或者网络波动,总之就是无法和NameNode进行通信

2、NameNode不会立即认为它挂了,要经过一段时间(超时时间)

3、HDFS默认超时时间10分钟+30秒

hdfs-site.xml

<!--参数为毫秒-->
<property>
 <name>dfs.namenode.heartbeat.recheck-interval</name>
 <value>300000</value>
</property>
<!--参数为秒-->
<property>
 <name>dfs.heartbeat.interval</name>
 <value>3</value>
</property>