hadoop之HDFS学习教程

Hadoop之HDFS

HDFS概述

HDFS产生背景

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

HDFS定义

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

HDFS优缺点

在这里插入图片描述

在这里插入图片描述

HDFS组成架构

在这里插入图片描述

HDFS文件块大小

HDFS的文件在物理上时分块存储,块的大小可以通过配置参数dfs.blocksize来规定,默认大小的hadoop2.x版本中是128m,老版本是64m

在这里插入图片描述

在这里插入图片描述

HDFS的shell操作

基本语法

  • hadoop fs 具体命令
  • hdfs dfs 具体命令

常用命令实操

准备工作
# 启动hdfs集群
[atguigu@hadoop102 hadoop-3.1.3]$ start-dfs.sh 
Starting namenodes on [hadoop102]
Starting datanodes
Starting secondary namenodes [hadoop104]
[atguigu@hadoop102 hadoop-3.1.3]$ my_jps.sh 
hadoop102,hadoop103,hadoop104进程启动情况
=================hadoop102 jps情况=================
1553 DataNode
1427 NameNode
1833 Jps
=================hadoop103 jps情况=================
1316 Jps
1245 DataNode
=================hadoop104 jps情况=================
1335 SecondaryNameNode
1418 Jps
1259 DataNode
上传
# -copyFromLocal:从本地服务器中拷贝到hdfs
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -copyFromLocal ./shuguo.txt /sanguo
# -moveFromLocal:从本地服务器中剪切到hdfs
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -moveFromLocal ./guanyu.txt /sanguo
# -appendToFile:追加一个文件到已经存在的文件末尾
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -appendToFile guanyu-zhuijia.txt /sanguo/guanyu.txt
# -put:等同于copyFormLocal
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -put guanyu-zhuijia.txt /sanguo
下载
# -copyToLocal:从HDFS拷贝到本地
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -copyToLocal /sanguo/guanyu.txt ./

# -get等同于copyToLocal,就是从HDFS下载文件到本地
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -get /sanguo/guanyu.txt ./

# -getmerge 合并下载多个文件
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -getmerge /sanguo/guanyu.txt /sanguo/shuguo.txt ./xiongdi.txt
HDFS直接操作
1)-ls: 显示目录信息
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -ls /
2)-mkdir:在HDFS上创建目录
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir -p /sanguo/shuguo
3)-cat:显示文件内容
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cat /sanguo/shuguo/kongming.txt
4)-chgrp 、-chmod、-chown:Linux文件系统中的用法一样,修改文件所属权限
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs  -chmod  666  /sanguo/shuguo/kongming.txt
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs  -chown  atguigu:atguigu   /sanguo/shuguo/kongming.txt
5)-cp :从HDFS的一个路径拷贝到HDFS的另一个路径
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -cp /sanguo/shuguo/kongming.txt /zhuge.txt
6)-mv:在HDFS目录中移动文件
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mv /zhuge.txt /sanguo/shuguo/
7)-tail:显示一个文件的末尾1kb的数据
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -tail /sanguo/shuguo/kongming.txt
8)-rm:删除文件或文件夹
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rm /sanguo/guanyu.txt
9)-rmdir:删除空目录
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -mkdir /test
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -rmdir /test
10)-du统计文件夹的大小信息
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du -s -h /user/atguigu/test
2.7 K  /user/atguigu/test

[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -du  -h /user/atguigu/test
1.3 K  /user/atguigu/test/README.txt
15     /user/atguigu/test/jinlian.txt
1.4 K  /user/atguigu/test/zaiyiqi.txt
11)-setrep:设置HDFS中文件的副本数量
[atguigu@hadoop102 hadoop-3.1.3]$ hadoop fs -setrep 10 /sanguo/shuguo/kongming.txt

HDFS客户端操作

JAVA客户端操作HDFS

HDFS客户端环境准备

- 在windows环境中添加Hadoop相关的依赖,配置Hadoop的环境变量
	- HADOOP_HOME
	- Path
- 把hadoop环境目录下的hadoop.dll和winutils.exe放在系统盘的/windows/System32下
- 执行java代码,如果不成功,重启电脑试试

添加hdfs的maven依赖

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

测试连接

	/**
     * 获取Hdfs客户端连接
     */
    @Test
    public void testCreateHdfsClient() throws IOException, InterruptedException {
        URI uri = URI.create("hdfs://hadoop102:9820");
        Configuration configuration = new Configuration();
        String user = "atguigu";
        //获取Hdfs客户端连接
        FileSystem fileSystem = FileSystem.get(uri, configuration, user);
        System.out.println(fileSystem.getClass().getName()); //测试ok
        fileSystem.close();
    }

HDFS文件上传

private FileSystem fs;

    /**
     * 获取Hdfs客户端连接
     */
    @Before
    public void init() throws IOException, InterruptedException {
        URI uri = URI.create("hdfs://hadoop102:9820");
        Configuration configuration = new Configuration();
        String user = "atguigu";
        //获取Hdfs客户端连接
        fs = FileSystem.get(uri, configuration, user);
        System.out.println(fs.getClass().getName());
    }

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

	@Test
    public void testCopyFromLocal () throws IOException {
        fs.copyFromLocalFile(false,
                true,
                new Path("D:/二次剪辑素材/hello.txt"),
                new Path("/java-api/upload/"));

    }

配置:配置的优先级 Configuration > hdfs-site.xml > hdfs-default.xml

HDFS文件下载

@Test
    public void testCopyToLocal () throws IOException {
        fs.copyToLocalFile(false,
                new Path("/java-api/upload/hello.txt"),
                new Path("C:/Users/Administrator.DESKTOP-FLGB82I/Desktop/大数据学习笔记/"),
                true);
        
        // 注意第四个参数为false时会下载文件的检验核,是一串16位进制的数据

    }

HDFS删除文件和目录

@Test
    public void testDelete() throws IOException {
        fs.delete(new Path("/java-api/upload/hello.txt"),true);
    }

HDFS文件更名和移动

@Test
    public void testRename() throws IOException {
        //移动文件
        fs.rename(new Path("/java-api/upload/hello.txt"),
                  new Path("/java-api/rename/"));

        //改名
        fs.rename(new Path("/java-api/rename/hello.txt"),
                  new Path("/java-api/rename/hello_rename.txt"));
    }

HDFS文件详情查看

@Test
    public void testListFiles() throws IOException {
        RemoteIterator<LocatedFileStatus> files = fs.listFiles(new Path("/"), true);
        while (files.hasNext()){
            LocatedFileStatus next = files.next();
            System.out.println("文件名:"+next.getPath().getName());
            System.out.println("块大小:"+next.getBlockSize());
            System.out.println("副本数:"+next.getReplication());
            System.out.println("权限信息:"+next.getPermission());
        }
    }

HDFS文件和文件夹判断

@Test
    public void testListStatus() throws IOException {
        FileStatus[] fileStatuses = fs.listStatus(new Path("/java-api/rename"));
        for (FileStatus status:fileStatuses) {
            if(status.isDirectory()){
                System.out.println("DIR:"+status.getPath().getName());
            }else{
                System.out.println("FILE:"+status.getPath().getName());
            }
        }
    }

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根据请求返回DataNode节点的策略?  -- 机架感知
	-- 如果当前Client所在机器有DataNode节点,那就返回当前机器DN1,否则从集群中随机一台
	-- 根据第一台机器的位置,然后再其他机架上随机一台,在第二台机器所在机架上再随机一台
	-- 以上策略的缘由:为了提高数据的可靠性,同时一定程度也保证数据传输的效率
	
-- 客户端建立传输通道的时候如果确定和哪一台DataNode先建立连接?	-- 网络拓扑
	-- 找离client最近的一台机器先建立通道(网络距离)

-- client为什么是以串行的方式建立通道
	-- 本质上就是为了降低client的IO开销
	
-- 数据传输的时候如果保证数据成功?
	-- 采用了ack回执的策略保证了数据完整成功上传

HDFS读数据流程

在这里插入图片描述

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

NameNode和SecondaryNameNode

NN和2NN工作机制

1.元数据信息要保存在哪
	- 保存到磁盘
		- 不足:读写速度慢,效率低
	- 保存到内存
		- 不足:数据不安全(断电丢失)
	- 最终解决方案: 磁盘 + 内存
	
2.元数据在磁盘与内存中如何进行同步(元数据的维护策略)
	- 当我们对元数据进行操作的时候,首先在内存中进行合并,其次还要把相关的操作记录追加到edits编辑日志文件		中,在满足一定条件下进行edits文件中的记录合并到元数据信息文件中fsimage
3.谁负责对NN的元数据信息进行合并?
	- 2NN主要负责对NN的元数据进行合并,当满足一定条件下,2NN会监测本地时间,每隔一个小时会主动对NN的		  edits文件和fsimage文件进行合并,合并的时候,首先会通知NN,这个时候NN就会停止对正在使用的edits文	  件的追加。同时会新建一个新的edits编辑日志文件,保证NN的正常工作。接下来会把NN本地的fsimage文件和		edits编辑日志拉取到2NN本地,在内存中对二者进行合并,最后产生最新的fsimage文件,把最新的fsimage文		件发送给NN的本地。注意,还有一个情况,当NN的edits文件中的操作次数累计达到100万次,即便还没到1小时,	 2NN也会进行合并。(2NN会没隔60秒监测一次NN方的edits文件的操作次数),
	 2NN也会自己把最新的fsimage文件备份一份

Fsimage和Edits解析

oiv查看Fsimage文件

[atguigu@hadoop102 current]$ pwd
/opt/module/hadoop-3.1.3/data/dfs/name/current

[atguigu@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000025 -o /opt/module/hadoop-3.1.3/fsimage.xml

[atguigu@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/fsimage.xml

oev查看Edits文件

[atguigu@hadoop102 current]$ hdfs oev -p XML -i edits_0000000000000000012-0000000000000000013 -o /opt/module/hadoop-3.1.3/edits.xml

[atguigu@hadoop102 current]$ cat /opt/module/hadoop-3.1.3/edits.xml

[atguigu@hadoop102 current]$ sz edits.xml # 下载到本地

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 >

集群安全模式

在这里插入图片描述

DataNode

DataNode工作机制

在这里插入图片描述

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

数据完整性

思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理DataNode节点上的数据损坏了,却没有发现,是否也很危险,那么如何解决呢?

如下是DataNode节点保证数据完整性的方法。

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

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

(3)Client读取其他DataNode上的Block。

(4)常见的校验算法 crc(32),md5(128),sha1(160)

(5)DataNode在其文件创建后周期验证CheckSum。

掉线时限参数设置

NN没有接受到DN时间可容许时间设置

在这里插入图片描述

需要注意的是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>

服役新数据节点

1)需求

随着公司业务的增长,数据量越来越大,原有的数据节点的容量已经不能满足存储数据的需求,需要在原有集群基础上动态添加新的数据节点。

2)环境准备

(1)在hadoop104主机上再克隆一台hadoop105主机

(2)修改IP地址和主机名称

(3)删除原来HDFS文件系统留存的文件(/opt/module/hadoop-3.1.3/data和logs)

(4)source一下配置文件

[atguigu@hadoop105 hadoop-3.1.3]$ source /etc/profile

(4)单节点启动datanode

[atguigu@hadoop105 hadoop-3.1.3]$ hdfs --daemon start datanode

刷新网页查看datanode集群

在这里插入图片描述

退役旧数据节点

添加白名单和黑名单

白名单和黑名单是hadoop管理集群主机的一种机制。

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

实际情况下,白名单用于确定允许访问NameNode的DataNode节点,内容配置一般与workers文件内容一致。 黑名单用于在集群运行过程中退役DataNode节点。

配置白名单和黑名单的具体步骤如下:

1)在NameNode节点的/opt/module/hadoop-3.1.3/etc/hadoop目录下分别创建whitelist 和blacklist文件

[atguigu@hadoop102 hadoop]$ pwd
/opt/module/hadoop-3.1.3/etc/hadoop
[atguigu@hadoop102 hadoop]$ touch whitelist
[atguigu@hadoop102 hadoop]$ touch blacklist
在whitelist中添加如下主机名称,假如集群正常工作的节点为102 103 104 105
hadoop102
hadoop103
hadoop104
hadoop105

# 黑名单暂时为空。

2)在hdfs-site.xml配置文件中增加dfs.hosts和 dfs.hosts.exclude配置参数

<!-- 白名单 -->
<property>
	<name>dfs.hosts</name>
	<value>/opt/module/hadoop-3.1.3/etc/hadoop/whitelist</value>
</property>
<!-- 黑名单 -->
<property>
	<name>dfs.hosts.exclude</name>
	<value>/opt/module/hadoop-3.1.3/etc/hadoop/blacklist</value>
</property>

3)分发配置文件whitelist,blacklist,hdfs-site.xml (注意:105节点也要发一份)

[atguigu@hadoop102 etc]$ xsync hadoop/ 
[atguigu@hadoop102 etc]$ rsync -av hadoop/ atguigu@hadoop105:/opt/module/hadoop-3.1.3/etc/hadoop/

4)重新启动集群(注意:105节点没有添加到workers,因此要单独起停)

[atguigu@hadoop102 hadoop-3.1.3]$ stop-dfs.sh
[atguigu@hadoop102 hadoop-3.1.3]$ start-dfs.sh
[atguigu@hadoop105 hadoop-3.1.3]$ hdfs –daemon start datanode

5)在web浏览器上查看目前正常工作的DN节点

在这里插入图片描述

黑名单退役

1)编辑/opt/module/hadoop-3.1.3/etc/hadoop目录下的blacklist文件

[atguigu@hadoop102 hadoop] vim blacklist
添加如下主机名称(要退役的节点)
hadoop105

2)分发blacklist到所有节点

[atguigu@hadoop102 hadoop]$ my_rsync ./blacklist
[atguigu@hadoop102 hadoop]$ scp -r ./blacklist atguigu@hadoop105:/opt/module/hadoop/

3)刷新NameNode、刷新ResourceManager

[atguigu@hadoop102 hadoop-3.1.3]$ hdfs dfsadmin -refreshNodes
Refresh nodes successful
[atguigu@hadoop102 hadoop-3.1.3]$ 

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

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

在这里插入图片描述

此外,还有一种白名单退役方式,就是直接从白名单中移除某台机器即可,然后再刷新集群

hdfs dfsadmin -refreshNodes,执行后发现105果然移除了,并且直接杀死了,不推荐这种做法

DataNode多目录配置

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

具体配置

(1)在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>

(2)停止集群,删除三台节点的data和logs中所有数据。

[atguigu@hadoop102 hadoop-3.1.3]$ rm -rf data/ logs/

[atguigu@hadoop103 hadoop-3.1.3]$ rm -rf data/ logs/

[atguigu@hadoop104 hadoop-3.1.3]$ rm -rf data/ logs/

(3)格式化集群并启动。

[atguigu@hadoop102 hadoop-3.1.3]$ bin/hdfs namenode –format

[atguigu@hadoop102 hadoop-3.1.3]$ sbin/start-dfs.sh

(4)查看结果

[atguigu@hadoop102 dfs]$ ll
总用量 12

drwx------. 3 atguigu atguigu 4096 44 14:22 data1

drwx------. 3 atguigu atguigu 4096 44 14:22 data2

drwxrwxr-x. 3 atguigu atguigu 4096 1211 08:03 name1

drwxrwxr-x. 3 atguigu atguigu 4096 1211 08:03 name2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值