简介
HDFS产生背景
随着数据量的增加,所有的数据都不能存储在本地文件系统中,需要将数据分配到更多的操作系统和文件管理系统,但管理和维护不方便,因此需要一个系统来管理存储所有数据的机器,即分布式文件管理系统,HDFS只是一种分布式文件管理系统。 
HDFS定义
HDFS(全称:Hadoop Distribute File System,Hadoop 用于文件存储和管理的分布式文件系统,通过目录树定位文件的。可以与Linux类比文件系统只包装了许多机器的文件管理功能。
HDFS优缺点
优点
- 高可靠性
- 数据自动保存多个副本(默认3个,可以通多dfs.replication通过添加副本来增加参数设置)
- 丢失的副本可以自动恢复
- 适合处理大量数据
- 数据规模:可处理GB,TB,甚至等级规模数据
- 文件规模:可处理规模以上的文件数量
- 它可以在便宜的机器上运行良好
缺点
- 不适用于秒级、毫秒级等低延迟数据访问
- 对大量小文件不友好
- 存储大量小文件会占用NameNode存储文件目录、块信息等元数据的大量内存,NameNode的
- 存储小文件的搜索时间将超过读取时间,搜索时间最好为传输时间的1%
- 不支持并发写入,随机修改文件
- 一个文件只能由一个线程编写,不允许同时编写多个线程
- 只支持增加文件内容(append),不支持随机修改
HDFS重要概念
HDFS 文件由统一命名空间目录树定位; 此外,它是分布式的,由许多服务器共同实现 其功能,集群中的服务器有自己的角色(分布式本质是拆分,各司其职);
- 典型的 Master/Slave 架构
HDFS 典型的架构 Master/Slave 结构。 HDFS集群通常是一个NameNode(HA会有两个架构NameNode,联邦机制) 多个DataNode组成; NameNode是集群的主节点,DataNode从节点集群。
- 分块存储(block机制)
HDFS 物理上,中文文件是分块存储的(block)的,块的大小可以通过配置参数来规定;Hadoop2.x默认版本block大小是128M;
- 命名空间(NameSpace)
HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。 Namenode 负责维护文件系统的名称空间,任何修改文件系统的名称空间或属性都将被修改Namenode 记录下来。 HDFS以访问形式向客户提供单一抽象目录树:hdfs://namenode的hostname:port/test/input hdfs://linux121:9000/test/input
- NameNode元数据管理
我们称目录结构和文件块位置信息为元数据。 NameNode记录每个文件对应的元数据block信息(block的id,以及所在的DataNode节点信息)
- DataNode数据存储
文件的各个 block 存储管理的具体原因 DataNode 承担节点block会有多个DataNode来存储,DataNode会定时向NameNode汇报你持有的block信息。
- 副本机制
为了容错,所有文件 block 每个文件都会有副本。 block 大小和副本系数都可以配置。应用程序可以指定文件的副本数量。文件创建时可以指定副本系数,也可以稍后更改。默认情况下,副本数量为3份。
- 一次写入,多次读出
HDFS 设计适合一次写入、多次读出的场景,不支持文件的随机修改。 正因为如此,支持追加写入,而不仅仅是随机更新。HDFS 适用于大数据分析的底层存储服务,不适用于网盘等应用(修改不 方便,延迟大,网络费用大,成本高)
HDFS架构

- Client:客户端
- 上传文件到HDFS当时,客户负责将文件分割block,然后上传
- 请求与NameNode交互,获取文件位置等元数据信息
- 读或写文件,和NameNode交互
- 使用一些命令管理和访问HDFS,比如对HDFS增删改查,NameNode格式化等操作
- NameNode(Master节点),集群管理者
- 维护和管理HDFS的名称空间(namespace)
- 维护副本策略
- 记录block的元数据
- 负责与客户端发送的读写请求
- DataNode(Slave节点),NameNode下达指令(老板),DataNode工作(弟弟)
- 保存实际数据块
- 负责数据块的读写
- Secondary NameNode
- 用来监控 HDFS 状态辅助后台程序,定期获取 HDFS 元数据快照定期合并Fsimage和Edits,并推送给NameNode。
- 辅助是最重要的功能 NameNode 管理元数据信息。
- 在紧急情况下,可以辅助恢复NameNode元数据信息
HDFS命令
若无配置 hadoop 环境变量,在 hadoop 在安装目录下bin目录中执行以下命令,如已配置 hadoop 可在任何目录下执行环境变量,
- 使用特定的命令
bin/hadoop fs 具体命令 或者 bin/hdfs dfs 具体命令
- 命令大全
span class="token punctuation">[root@node101 ~]# hdfs dfs
Usage: hadoop fs [generic options]
[-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] [-l] [-d] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-x] <path> ...]
[-expunge]
[-find <path> ... <expression> ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {
-n name | -d} [-e en] <path>]
[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{
-b|-k} {
-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setfattr {
-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]
Generic options supported are:
-conf <configuration file> specify an application configuration file
-D <property=value> define a value for a given property
-fs <file:///|hdfs://namenode:port> specify default filesystem URL to use, overrides 'fs.defaultFS' property from configurations.
-jt <local|resourcemanager:port> specify a ResourceManager
-files <file1,...> specify a comma-separated list of files to be copied to the map reduce cluster
-libjars <jar1,...> specify a comma-separated list of jar files to be included in the classpath
-archives <archive1,...> specify a comma-separated list of archives to be unarchived on the compute machines
The general command line syntax is:
command [genericOptions] [commandOptions]
常用命令
[root@node101 ~]# hdfs dfs -help rm
-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ... :
Delete all files that match the specified file pattern. Equivalent to the Unix
command "rm <src>"
-f If the file does not exist, do not display a diagnostic message or
modify the exit status to reflect an error.
-[rR] Recursively deletes directories.
-skipTrash option bypasses trash, if enabled, and immediately deletes <src>.
-safely option requires safety confirmation, if enabled, requires
confirmation before deleting large directory with more than
<hadoop.shell.delete.limit.num.files> files. Delay is expected when
walking over large directory recursively to count the number of
files to be deleted before the confirmation.
[root@node101 ~]# hdfs dfs -ls /
[root@node101 ~]# hdfs dfs -mkdir -p /bigdata
# 创建test.txt空文件,里边没有任何内容
[root@node101 ~]# vi test.txt
# 查询test.txt文件
[root@node101 ~]# ls test.txt
test.txt
#剪切test.txt文件到hdfs上bigdata文件夹
[root@node101 ~]# hdfs dfs -moveFromLocal ./test.txt /bigdata
#查看hdfs上/bigdata文件夹,test.txt文件已上传
[root@node101 ~]# hdfs dfs -ls /bigdata
Found 1 items
-rw-r--r-- 3 root supergroup 31 2022-07-26 18:13 /bigdata/test.txt
#查询本地test.txt文件 报错,原因已经将test.txt剪切到hdfs
[root@node101 ~]# ls test.txt
ls: cannot access test.txt: No such file or directory
# 查看本地wc.txt文件
[root@node101 ~]# ls wc.txt
wc.txt
# 从本地上传wc.txt文件到hdfs上/bigdata目录
[root@node101 ~]# hdfs dfs -copyFromLocal wc.txt /bigdata
[root@node101 ~]# hdfs dfs -ls /bigdata
Found 2 items
-rw-rw-rw- 10 root root 45 2022-07-26 18:33 /bigdata/test.txt
-rw-r--r-- 3 root supergroup 42 2022-07-26 21:10 /bigdata/wc.txt
# 查看本地还存在wc.txt文件
[root@node101 ~]# ls wc.txt
wc.txt
# 查询hdfs上test.txt文件内容,此时为空
[root@node101 ~]# hdfs dfs -cat /bigdata/test.txt
# 在本地创建test2.txt并输入一些单词
[root@node101 ~]# vi test2.txt
#查看test2.txt内容
[root@node101 ~]# cat test2.txt
hadoop hive
hadoop spark
bigdata flink
hbase
# 追加test2.txt 内容到hdfs上的/bigdata/test.txt文件
[root@node101 ~]# hdfs dfs -appendToFile test2.txt /bigdata/test.txt
# 再次查看hdfs上/bigdata/test.txt文件,内容已经变化
[root@node101 ~]# hdfs dfs -cat /bigdata/test.txt
hadoop hive
hadoop spark
bigdata flink
hbase
# 查看文件权限
[root@node101 ~]# hdfs dfs -ls /bigdata/test.txt
-rw-r--r-- 3 root supergroup 45 2022-07-26 18:33 /bigdata/test.txt
# 修改文件权限
[root@node101 ~]# hdfs dfs -chmod 666 /bigdata/test.txt
# 再次查看文件权限
[root@node101 ~]# hdfs dfs -ls /bigdata/test.txt
-rw-rw-rw- 3 root supergroup 45 2022-07-26 18:33 /bigdata/test.txt
# 修改文件所属
[root@node101 ~]# hdfs dfs -chown root:root /bigdata/test.txt
# 再次查看文件所属
[root@node101 ~]# hdfs dfs -ls /bigdata/test.txt
-rw-rw-rw- 3 root root 45 2022-07-26 18:33 /bigdata/test.txt
# 查看hdfs上/bigdata目录下文件
[root@node101 ~]# hdfs dfs -ls /bigdata/
Found 1 items
-rw-rw-rw- 3 root root 45 2022-07-26 18:33 /bigdata/test.txt
# 拷贝本地test2.txt文件到hdfs
[root@node101 ~]# hdfs dfs -copyFromLocal test2.txt /bigdata
# 再次查看hdfs上/bigdata目录下文件,test2.txt已经上传
[root@node101 ~]# hdfs dfs -ls /bigdata/
Found 2 items
-rw-rw-rw- 3 root root 45 2022-07-26 18:33 /bigdata/test.txt
-rw-r--r-- 3 root supergroup 45 2022-07-26 19:05 /bigdata/test2.txt
# 删除本地test2.txt文件
[root@node101 ~]# rm -rf test2.txt
# 查看文件已删除
[root@node101 ~]# ls test2.txt
ls: cannot access test2.txt: No such file or directory
# 从hdfs拷贝test2.txt文件到本地
[root@node101 ~]# hdfs dfs -copyToLocal /bigdata/test2.txt
# 查看文件已经被拷贝到本地
[root@node101 ~]# ls test2.txt
test2.txt
# 创建一个hdfs新目录 /bigdata2
[root@node101 ~]# hdfs dfs -mkdir /bigdata2
# 查看/bigdata2目录下没有文件
[root@node101 ~]# hdfs dfs -ls /bigdata2
# 从/bigdata目录拷贝test2.txt文件到/bigdata2
[root@node101 ~]# hdfs dfs -cp /bigdata/test2.txt /bigdata2
# 再次查看bigdata2文件夹已经多了test2文件
[root@node101 ~]# hdfs dfs -ls /bigdata2
Found 1 items
-rw-r--r-- 3 root supergroup 45 2022-07-26 19:20 /bigdata2/test2.txt
# 查看bigdata文件夹下test2.txt文件依然在
[root@node101 ~]# hdfs dfs -ls /bigdata
Found 2 items
-rw-rw-rw- 3 root root 45 2022-07-26 18:33 /bigdata/test.txt
-rw-r--r-- 3 root supergroup 45 2022-07-26 19:05 /bigdata/test2.txt
# 删除bigdata2文件夹下的test2.txt文件
[root@node101 ~]# hdfs dfs -rm /bigdata2/test2.txt
Deleted /bigdata2/test2.txt
# 文件已删除,查看文件报错提示文件不存在
[root@node101 ~]# hdfs dfs -ls /bigdata2/test2.txt
ls: `/bigdata2/test2.txt': No such file or directory
# 从bigdata文件夹下移动test2.txt文件到bigdata2文件夹
[root@node101 ~]# hdfs dfs -mv /bigdata/test2.txt /bigdata2
# 查看bigdata目录下的test2.txt文件已不存在
[root@node101 ~]# hdfs dfs -ls /bigdata
Found 1 items
-rw-rw-rw- 3 root root 45 2022-07-26 18:33 /bigdata/test.txt
# 查看bigdata2文件加下已有test2.txt文件
[root@node101 ~]# hdfs dfs -ls /bigdata2
Found 1 items
-rw-r--r-- 3 root supergroup 45 2022-07-26 19:05 /bigdata2/test2.txt
[root@node101 ~]# hdfs dfs -tail /bigdata/test.txt
hadoop hive
hadoop spark
bigdata flink
hbase
# 查看hdfs上/bigdata/test.txt文件内容
[root@node101 ~]# hdfs dfs -cat /bigdata/test.txt
hadoop hive
hadoop spark
bigdata flink
hbase
# 查看hdfs上/bigdata/wc.txt文件内容
[root@node101 ~]# hdfs dfs -cat /bigdata/wc.txt
lwp spark flink lwp
hadoop flink hive
mr
# 合并/bigdata/test.txt和/bigdata/wc.txt文件内容 到本地merge.txt
[root@node101 ~]# hdfs dfs -getmerge /bigdata/* merge.txt
# 查看合并后的文件内容
[root@node101 ~]# cat merge.txt
hadoop hive
hadoop spark
bigdata flink
hbase
lwp spark flink lwp
hadoop flink hive
mr
[root@node101 ~]# hdfs dfs -df /
Filesystem Size Used Available Use%
hdfs://node101:9000 109443035136 1231085568 91952766976 1%
[root@node101 ~]# hdfs dfs -df -h /
Filesystem Size Used Available Use%
hdfs://node101:9000 101.9 G 1.1 G 85.6 G 1%
[root@node101 ~]# hdfs dfs -du -s -h /bigdata
45 /bigdata
[root@node101 ~]# hdfs dfs -du -h /bigdata
45 /bigdata/test.txt
[root@node101 ~]# hdfs dfs -count /bigdata
1 2 87 /bigdata
目录数量 文件数量 文件总大小 统计目录
[root@node101 ~]# hdfs dfs -expunge
[root@node101 ~]# hdfs dfs -setrep 10 /bigdata/test.txt
Replication 10 set: /bigdata/test.txt
在NameNode页面查看test.txt文件元数据信息replication为10  **需要注意:**这里设置的副本数只是记录在NameNode的元数据中,是否真的会有这么多副本,还得看DataNode的 数量。因为目前只有3台设备,最多也就3个副本,只有节点数的增加到10台时,副本数才能达到10。
高级命令
在多人共用HDFS的环境下,配额设置非常重要。特别是在 Hadoop 处理大量资料的环境,如果没有配额管理,很容易把所有的空间用完造成别人无法存取。HDFS 的配额设定是针对目录而不是针对账号,可以让每个账号仅操作某一个目录,然后对目录设置配置。
HDFS 文件的限额配置允许我们以文件个数,或者文件大小来限制我们在某个目录下上传的文件数量或者文件内容总量,以便达到我们类似百度网盘网盘等限制每个用户允许上传的最大的文件的量。
# 查看配额信息
[root@node101 ~]# hdfs dfs -count -q -h /
8.0 E 8.0 E none inf 82 382 386.5 M /
# 新建hdfs上/bigdata3文件夹
[root@node101 ~]# hdfs dfs -mkdir /bigdata3
# 上传两个文件到/bigdata3目录下
[root@node101 ~]# hdfs dfs -put test2.txt wc.txt /bigdata3
# 删除/bigdata3目录下两个文件
[root@node101 ~]# hdfs dfs -rm -r -f /bigdata3/*
Deleted /bigdata3/test2.txt
Deleted /bigdata3/wc.txt
# 对/bigdata3文件夹做配额限制,限制最多上传两个文件
[root@node101 ~]# hdfs dfsadmin -setQuota 2 /bigdata3
# 再次上传两个文件,发现上传失败,有文件数量限制,只上传成功了一个文件
[root@node101 ~]# hdfs dfs -put test2.txt wc.txt /bigdata3
put: The NameSpace quota (directories and files) of directory /bigdata3 is exceeded: quota=2 file count=3
[root@node101 ~]# hdfs dfs -ls /bigdata3
Found 1 items
-rw-r--r-- 3 root supergroup 45 2022-07-26 21:43 /bigdata3/test2.txt
# 清除/bigdata3配额设置
[root@node101 ~]# hdfs dfsadmin -clrQuota /bigdata3
# 再次上传文件成功
[root@node101 ~]# hdfs dfs -put test2.txt wc.txt /bigdata3
put: `/bigdata3/test2.txt': File exists
[root@node101 ~]# hdfs dfs -ls /bigdata3
Found 2 items
-rw-r--r-- 3 root supergroup 45 2022-07-26 21:43 /bigdata3/test2.txt
-rw-r--r-- 3 root supergroup 42 2022-07-26 21:48 /bigdata3/wc.txt
在设置空间配额时,设置的空间至少是 block_size * 3 大小
# 设置空间配额
[root@node101 ~]# hdfs dfsadmin -setSpaceQuota 10K /bigdata3
# 生成任意大小文件
[root@node101 ~]# dd if=/dev/zero of=test3.txt bs=1M count=2
2+0 records in
2+0 records out
2097152 bytes (2.1 MB) copied, 0.00387978 s, 541 MB/s
# test3.txt文件超过设置的空间配额,上传失败
[root@node101 ~]# hdfs dfs -put test3.txt /bigdata3
put: The DiskSpace quota of /bigdata3 is exceeded: quota = 10240 B = 10 KB but diskspace consumed = 402653184 B = 384 MB
# 请出空间配额限制,上传文件成功
[root@node101 ~]# hdfs dfsadmin -clrSpaceQuota /bigdata3
[root@node101 ~]# hdfs dfs -put test3.txt /bigdata3
[root@node101 ~]# hdfs dfs -ls /bigdata3
Found 1 items
-rw-r--r-- 3 root supergroup 2097152 2022-07-26 22:00 /bigdata3/test3.txt
。当集群启动的时候,会首先进入安全模式。当系统处于安全模式时会检查数据块的完整性。 假设我们设置的副本数(即参数dfs.replication)是3,那么在datanode上就应该有3个副本存在,假设只存在2个副本,那么比例就是2/3=0.666。hdfs默认的副本率0.999。我们的副本率0.666明显小于0.999,因此系统会自动的复制副本到其他dataNode,使得副本率不小于0.999。如果系统中有5个副本,超过我们设定的3个副本,那么系统也会删除多于的2个副本。 **在安全模式状态下,文件系统只接受读数据请求,而不接受删除、修改等变更请求。**在当整个系统达到安全标准时,HDFS自动离开安全模式。30s安全模式操作命令
hdfs dfsadmin -safemode get #查看安全模式状态
hdfs dfsadmin -safemode enter #进入安全模式
hdfs dfsadmin -safemode leave #离开安全模式
HDFS java客户端操作
准备客户端操作环境
- 将Hadoop-2.9.2安装包解压到非中文路径(例如:D:\lwp\hadoop-2.9.2)。

- 配置HADOOP_HOME环境变量

- 修改Path变量,增加%HADOOP_HOME%\bin

- 在IDEA创建新的maven项目
- 添加pom.xml依赖和相关配置
<dependencies>
<!--hadoop相关-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.9.2</version>
</dependency>
<!--日志配置-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependencies>
为了便于控制程序运行打印的日志数量,需要在项目的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
- 创建包名com.hadoop.hdfs和类,并测试
package com.hadoop.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
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 URISyntaxException, IOException, InterruptedException {
//1.获取hadoop集群的configuration对象
Configuration configuration = new Configuration();
//2.根据configuration获取FileSystem对象
FileSystem fileSystem = FileSystem.get(new URI("hdfs://node101:9000"), configuration, "root");
//3.创建文件夹
fileSystem.mkdirs(new Path("/bigdata4"));
//4.释放FileSystem对象(类似于关闭数据库连接)
fileSystem.close();
}
}
可能遇到的问题
- 如果不指定操作HDFS集群的用户信息,默认是获取当前操作系统的用户信息,出现权限被拒绝的问
题,报错如下: 2. windows解压安装Hadoop后,在调用相关API操作HDFS集群时可能会报错,这是由于Hadoop安装缺少windows操作系统相关文件所致,如下图: 解决方案: 把winutils.exe拷贝放到windows系统Hadoop安装目录的bin目录下即可!!
HDFS的API操作
测试参数优先级
- 编写文件上传代码
@Test
public void testCopyFromLocalFile() throws IOException,
InterruptedException, URISyntaxException {
// 1 获取文