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