hadoop——day4、5(HDFS)

HDFS

在这里插入图片描述

在这里插入图片描述

1.HDFS概述

1)HDFS定义

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

HDFS的使用场景:
适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭之后就不需要改变。

2)优缺点:

优:

  • 高容错
    数据自动北方多个副本
    某个副本丢失,可以自动恢复
  • 适合大数据处理
  • 可以构建在廉价服务器上

缺:

  • 不适合低延时数据访问,毫秒级别做不到(mysql做得到)

  • 无法高效对大量的小文件进行存储

    大量小文件,占用NameNode大量的内存来存储文件目录和信息块,资源有限
    小文件的寻址可能超过读取时间,违背hdfs设计目标

  • 不支持并发写入,不支持文件随机修改(只能追加)

3)架构组成

在这里插入图片描述

  • NameNode(nn): 主管者
    管理hdfs名称空间
    配置副本策略
    管理数据块(block)映射信息
    处理客户端读写信息

  • DataNode:干活的,执行命令的
    存储实际的数据块
    执行数据块的读/写

  • Client: 客户端

    文件切分,文件上传hdfs时候,Client把文件切分为一个个的block,然后上传
    与Namenode交互,获取文件的位置
    与Datenode交互,读/写
    相关命令管理HDFS,比如格式化Namenode

  • SecondaryNameNode(2nn):秘书, 并不是NameNode的热备(NameNode挂掉,他不是马上代替它):
    辅助NameNode,分担工作
    紧急情况恢复NameNode,但不是完全恢复,毕竟是秘书

4)文件块大小(*面试题)

在这里插入图片描述

固态硬盘传输速率 200 - 300M/s 所以块的大小选择256M
机械硬盘:100M/s 块选128M

思考:为什么块的大小不能设置太大,或者太小?

  • 太小,增加寻址时间,
  • 太大,磁盘的传输数据明显大于定位这个块的所需的数据,导致程序程序处理这块数据效率低下

总结:HDFS块的大小取决于磁盘传输速率

2.HDFS的shell操作(*开发重点)

2.1 基本的语法:hadoop fs + 具体命令
或者,hdfs dfs + 具体命令(两者是一样的)

2.2 常用命令操作:

1. 准备工作

1)启动Hadoop集群(方便后续的测试)
2)-help:输出这个命令参数
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -help rm
3)创建/sanguo文件夹
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /sanguo

2. 上传

1)-moveFromLocal:从本地剪切粘贴到HDFS
[atguigu@hadoop102 hadoop-3.1.3]$ vim shuguo.txt
输入:
shuguo

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -moveFromLocal ./shuguo.txt /sanguo

2)-copyFromLocal:从本地文件系统中拷贝文件到HDFS路径去
[atguigu@hadoop102 hadoop-3.1.3]$ vim weiguo.txt
输入:
weiguo

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -copyFromLocal weiguo.txt /sanguo

3)-put:等同于copyFromLocal,生产环境更习惯用put
[atguigu@hadoop102 hadoop-3.1.3]$ vim wuguo.txt
输入:
wuguo

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -put ./wuguo.txt /sanguo

4)-appendToFile:追加一个文件到已经存在的文件末尾
[atguigu@hadoop102 hadoop-3.1.3]$ vim liubei.txt
输入:
liubei

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -appendToFile liubei.txt /sanguo/shuguo.txt

3. 下载

1)-copyToLocal:从HDFS拷贝到本地
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -copyToLocal /sanguo/shuguo.txt ./

2)-get:等同于copyToLocal,生产环境更习惯用get
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -get /sanguo/shuguo.txt ./shuguo2.txt

4. HDFS直接操作

1)-ls: 显示目录信息
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /sanguo

2)-cat:显示文件内容
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cat /sanguo/shuguo.txt

3)-chgrp、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chmod 666 /sanguo/shuguo.txt
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -chown atguigu:atguigu /sanguo/shuguo.txt

4)-mkdir:创建路径
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /jinguo

5)-cp:从HDFS的一个路径拷贝到HDFS的另一个路径
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cp /sanguo/shuguo.txt /jinguo

6)-mv:在HDFS目录中移动文件
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/wuguo.txt /jinguo
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /sanguo/weiguo.txt /jinguo

7)-tail:显示一个文件的末尾1kb的数据
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -tail /jinguo/shuguo.txt

8)-rm:删除文件或文件夹
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm /sanguo/shuguo.txt

9)-rm -r:递归删除目录及目录里面内容
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm -r /sanguo

10)-du统计文件夹的大小信息
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du -s -h /jinguo
27 81 /jinguo(因为设置了三台机子副本 27*3=81)

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du -h /jinguo
14 42 /jinguo/shuguo.txt
7 21 /jinguo/weiguo.txt
6 18 /jinguo/wuguo.tx
说明:27表示文件大小;81表示27*3个副本;/jinguo表示查看的目录

11)-setrep:设置HDFS中文件的副本数量
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -setrep 10 /jinguo/shuguo.txt

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

3.HDFS的API操作(涉及到Maven操作?一下午学习Maven了)

客户端环境准备

1)找到资料包路径下的Windows依赖文件夹,拷贝hadoop-3.1.0到非中文路径(比如d:\)。
2)配置HADOOP_HOME环境变量
3)配置Path环境变量。
注意:如果环境变量不起作用,可以重启电脑试试。

验证:
Hadoop环境变量是否正常?双击winutils.exe,闪退就是成功了

如果报如下错误。说明缺少微软运行库(正版系统往往有这个问题)。再资料包里面有对应的微软运行库安装包双击安装即可。

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

<dependencies>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</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>

报错:version报错:
CSDN上搜索后,把这个项目的pom.xml文件拖到maven的bin目录下,然后cmd到mavenbin目录下,执行mvn clean install 慢慢等他下载。

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

5)创建包名:com.wts.hdfs
6)创建HdfsClient类

package com.wts.hdfs;

import org.apache.hadoop.conf.Configuration;//都要选hadoop的包
import org.apache.hadoop.fs.FileSystem;//选hadoop的包
import org.apache.hadoop.fs.Path;
import org.junit.Test;


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


public class HdfsClient {

    @Test
    public void testMkdirs() throws IOException, URISyntaxException, InterruptedException {

        //连接集群nn地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //创建一个配置文件
        Configuration configuration = new Configuration();

        //user
        String user = "wts";

        //1.获取客户端对象
        FileSystem fs = FileSystem.get(uri, configuration, user);

        //2.创建一个文件夹
        fs.mkdirs(new Path("/xiyou/huahuoshan"));

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

封装代码:

package com.wts.hdfs;

import org.apache.hadoop.conf.Configuration;//都要选hadoop的包
import org.apache.hadoop.fs.FileSystem;//选hadoop的包
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 HdfsClient {

    private FileSystem fs;//  ctrl + alt + enter 升级为全局变量

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        //连接集群nn地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //创建一个配置文件
        Configuration configuration = new Configuration();
        //user
        String user = "wts";

        //1.获取客户端对象
        this.fs = FileSystem.get(uri, configuration, user);
    }

    @After
    public void close() throws IOException {
        //3.关闭资源
        fs.close();
    }

    @Test
    public void testMkdirs() throws IOException, URISyntaxException, InterruptedException {
        //2.创建一个文件夹
        fs.mkdirs(new Path("/xiyou/huahuoshan"));
    }
}

7)执行程序 多了/xiyou/huaguoshan文件夹
在这里插入图片描述

文件上传

1.fs.copyFromLocalFile:参数解读
在这里插入图片描述2.写代码:写在最后一行了

package com.wts.hdfs;

import org.apache.hadoop.conf.Configuration;//都要选hadoop的包
import org.apache.hadoop.fs.FileSystem;//选hadoop的包
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 HdfsClient {

    private FileSystem fs;//  ctrl + alt + enter 升级为全局变量

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        //连接集群nn地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //创建一个配置文件
        Configuration configuration = new Configuration();
        //user
        String user = "wts";

        //1.获取客户端对象
        this.fs = FileSystem.get(uri, configuration, user);
    }

    @After
    public void close() throws IOException {
        //3.关闭资源
        fs.close();
    }

    @Test
    public void testMkdirs() throws IOException, URISyntaxException, InterruptedException {
        //2.创建一个文件夹
        fs.mkdirs(new Path("/xiyou/huahuoshan"));
    }

    //上传数据
    @Test
    public void putFile() throws IOException {
        fs.copyFromLocalFile(false, false, new Path("G:\\1_Program\\hadoop_learning\\myshare\\sunwukong.txt"), new Path("hdfs://hadoop102:8020/xiyou/huaguoshan"));
    }
}

  1. 参数优先级排序:
    客户端代码中设置的值 >
    ClassPath下的用户自定义配置文件(resourses) >
    然后是服务器的自定义配置(xxx-site.xml) >
    服务器的默认配置(xxx-default.xml)

例:采用上述代码
1) 按图设置resources文件,创建hdfs-site.xml,写入一下内容:
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
</configuration>

可以看到集群副本变为1

2) 在HDFSClient类中,在配置文件configuration时候,如图设置参数:
在这里插入图片描述

在这里插入图片描述
运行程序可以看到集群副本为2

在这里插入图片描述

文件下载

1)参数解读
在这里插入图片描述

2)代码运行

package com.wts.hdfs;

import org.apache.hadoop.conf.Configuration;//都要选hadoop的包
import org.apache.hadoop.fs.FileSystem;//选hadoop的包
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 HdfsClient {

    private FileSystem fs;//  ctrl + alt + enter 升级为全局变量

    @Before
    public void init() throws URISyntaxException, IOException, InterruptedException {
        //连接集群nn地址
        URI uri = new URI("hdfs://hadoop102:8020");
        //创建一个配置文件
        Configuration configuration = new Configuration();
        //user
        configuration.set("dfs.replication", "2");

        String user = "wts";

        //1.获取客户端对象
        this.fs = FileSystem.get(uri, configuration, user);
    }

    @After
    public void close() throws IOException {
        //3.关闭资源
        fs.close();
    }

    //@Test
    public void testMkdirs() throws IOException, URISyntaxException, InterruptedException {
        //2.创建一个文件夹
        fs.mkdirs(new Path("/xiyou/huahuoshan"));
    }

    //上传数据
    @Test
    public void putFile() throws IOException {
        fs.copyFromLocalFile(false, true, new Path("G:\\1_Program\\hadoop_learning\\myshare\\sunwukong.txt"),
                new Path("/xiyou/huaguoshan/"));
    }


    //文件下载
    @Test
    public void getFile() throws IOException {
        fs.copyToLocalFile(false, new Path("/xiyou/huaguoshan"),
                new Path("G:\\1_Program\\hadoop_learning\\myshare\\getfile"), false);
    }

}

文件删除

1)参数解读
在这里插入图片描述

文件改名和移动

    //文件改名和移动
    @Test
    public void mvFile() throws IOException {
        fs.rename(new Path("/myfile"), new Path("/mynewname"));
    }

在这里插入图片描述

查看文件详细信息

 //查看文件详细信息
    @Test
    public void listFile() throws IOException {
        RemoteIterator<LocatedFileStatus> locatedFiles = fs.listFiles(new Path("/"), true);

        while(locatedFiles.hasNext()){
            LocatedFileStatus FileStatus = locatedFiles.next();

            System.out.println("==========" + FileStatus.getPath() + "==========");
            System.out.println(FileStatus.getPermission());
            System.out.println(FileStatus.getOwner());
            System.out.println(FileStatus.getGroup());
            System.out.println(FileStatus.getLen());//!查看文件的大小比较特殊
            System.out.println(FileStatus.getModificationTime());
            System.out.println(FileStatus.getReplication());
            System.out.println(FileStatus.getBlockSize());
            System.out.println(FileStatus.getPath().getName());//!查看文件的名称比较特殊

            //获取块信息
            BlockLocation[] blockLocations = FileStatus.getBlockLocations();
            System.out.println(Arrays.toString(blockLocations));
        }
    }

HDFS文件和文件夹的判断

    //判断是文件还是文件夹。
    @Test
    public void listStatus() throws IOException {
        FileStatus[] fileStatuses = fs.listStatus(new Path("/"));
        for (FileStatus fileStatus : fileStatuses) {
            if (fileStatus.isFile())
                System.out.println(fileStatus.getPath().getName() + "是个文件");
            else {
                System.out.println(fileStatus.getPath().getName() + "是个文件夹");
            }
        }
    }

4.19

4.19今日小结:
  学习进度很慢,简单复习回顾一下hdfs的API操作,所谓的API操作就是写代码在idea上操作Hadoop的文件,
  首先,显示配置maven的环境,首先你要创建maven的工程项目,学了一下午,皮毛
  然后,在maven工程下面写入相关的坐标和库,注意报错,可能没安装插件
  然后先在resources里面创建应该是跟日志相关的代码
  然后,在java下创建com.wts的包、HDFSClient类咯,写代码的时候注意封装的思想:先在创建客户端对象的时候配置相关的nn和configruation配置文件;然后是fs.mkdir,创建文件夹咯;然后是关闭资源文件
  ------学到一个有意思的地方@Test可以单元测试代码,还挺灵性的
  ------升级全局变量的操作快捷键 nb
  ------.sout .for 
  然后增删改查
  增:就是put,但是代码要写copyfromlocalfile,需要注意的是各个参数的意思;还有参数的优先级别
  下载,copytolocalfile
  删:fs.delete()
  改只能改名字和移动位置:都是用rename
  查只能查详细的信息:fs.listfile
  然后判断是否是文件夹:fs.liststatus
  -------
  确实学的有点慢了,第一天写日小结,明天再接再厉,持续学习。

4.HDFS读写流程(*面试重点)

写数据流程

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

2) 网络拓扑–节点距离计算

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

在这里插入图片描述

在这里插入图片描述
3)机架感知

在这里插入图片描述

读数据流程

在这里插入图片描述

5.nn和2nn(了解)

工作机制和解析

思考:NameNode中的元数据是存储在哪里的?

磁盘中备份元数据的FsImage。

引入Edits文件(只进行追加操作,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并追加到Edits中。

这样,一旦NameNode节点断电,可以通过FsImage和Edits的合并,合成元数据。SecondaryNamenode,专门用于FsImage和Edits的合并。
在这里插入图片描述

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

查看Fsimage和Edits

1)查看Fsimage
hdfs oiv -p 文件类型 -i 镜像文件 -o 转换后文件输出路径:

[wts@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current
[wts@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000457 -o /opt/software/fs
image.xml
[wts@hadoop102 software]$ sz fsimage.xml (下载到桌面上了)

2)查看Edits
hdfs oev -p 文件类型 -i 编辑日志 -o 转换后文件输出路径:

[wts@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current
[wts@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000458-0000000000000000466 -
o /opt/software/edits.xml
[wts@hadoop102 software]$ sz edits.xml

思考:NameNode如何确定下次开机启动的时候合并哪些Edits?
答:比fsimage566大的合并

检查点的时间设置

CheckPoint时间设置
1)通常情况下,SecondaryNameNode每隔一小时执行一次。
[hdfs-default.xml]

<property>
  <name>dfs.namenode.checkpoint.period</name>
  <value>3600s</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>60s</value>
<description> 1分钟检查一次操作次数</description>
</property>

6.DateNode(理解)

dn工作机制

[wts@hadoop102 subdir0]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/data/current/BP-1679317250-192.168.10.102-1649994214843/c
urrent/finalized/subdir0/subdir0

在这里插入图片描述
(1)一个数据块在DataNode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
(2)DataNode启动后向NameNode注册,通过后,周期性(6小时)的向NameNode上报所有的块信息
DN向NN汇报当前解读信息的时间间隔,默认6小时;

<property>
	<name>dfs.blockreport.intervalMsec</name>
	<value>21600000</value>
	<description>Determines block reporting interval in milliseconds.</description>
</property>

DN扫描自己节点块信息列表的时间,默认6小时

<property>
	<name>dfs.datanode.directoryscan.interval</name>
	<value>21600s</value>
	<description>Interval in seconds for Datanode to scan data directories and reconcile the difference between blocks in memory and on the disk.
	Support multiple time unit suffix(case insensitive), as described
	in dfs.heartbeat.interval.
	</description>
</property>

(3)心跳是每3秒一次,心跳返回结果带有NameNode给该DataNode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟+30s没有收到某个DataNode的心跳,则认为该节点不可用。

(4)集群运行中可以安全加入和退出一些机器。

数据完整性

在这里插入图片描述
采用crc校验

    //文件下载
    @Test
    public void getFile() throws IOException {
        fs.copyToLocalFile(false, new Path("/xiyou/huaguoshan"),
                new Path("G:\\1_Program\\hadoop_learning\\myshare\\getfile"), false);//false是开启校验
    }

掉线是限参数设置

在这里插入图片描述
需要注意的是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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值