目录
1、HDFS简介
1.1 什么是HDFS
1.2 HDFS的优点
1.3、HDFS的架构
1.3.1、 NameNode
1.3.2、 NameNode的职责
1.3.3、DataNode
1.3.4、 DataNode的职责
1.3.5、Secondary NameNode
1.3.6、Secondary NameNode的职责
2、HDFS的工作原理
2.1、文件存储
2.2 、数据写入
2.3、 数据读取
2.4、 容错机制
2.5、元数据管理
3、HDFS的Shell操作
4、HDFS的API操作
4.1、配置客户端环境变量
4.2、客户端api的使用
5、参考
6、附录
1、window环境下的hadoop依赖
2、完整代码
1、HDFS简介
1.1 什么是HDFS
HDFS是Hadoop生态系统中的一个分布式文件系统,旨在在集群的廉价硬件上可靠地存储大数据集。HDFS设计为高容错,并为高吞吐量数据访问而优化,适用于在商用硬件上运行的大数据应用。
1.2 HDFS的优点
- 高容错性:数据通过副本机制存储在多个节点上,确保在硬件故障时数据的高可用性。
- 高吞吐量:通过批量处理大数据,HDFS优化了数据的读写速度。
- 可扩展性:通过添加节点,可以轻松扩展HDFS的存储容量和计算能力。
- 可靠性:通过分布式架构和数据冗余,确保数据在系统故障情况下的完整性和可用性。
1.3、HDFS的架构
HDFS采用主从架构,主要由NameNode和DataNode两类节点组成。
1.3.1、 NameNode
NameNode是HDFS的主节点,负责管理文件系统的命名空间和文件块的映射关系。它存储所有文件和目录的元数据(如文件名、权限、块位置等),并协调客户端对数据的访问请求。
1.3.2、 NameNode的职责
文件系统命名空间管理:管理文件和目录的结构,维护元数据。
- 块管理:管理文件与块的映射关系,以及块在DataNode上的存储位置。
- 集群管理:监控DataNode的健康状态,处理节点故障。
1.3.3、DataNode
DataNode是HDFS的工作节点,负责存储实际的数据块。每个DataNode定期向NameNode发送心跳信号,报告其健康状态和存储情况。
1.3.4、 DataNode的职责
- 数据存储:存储HDFS文件的数据块。
- 数据块报告:定期向NameNode发送数据块列表,报告其存储情况。
- 数据块操作:执行客户端请求的读写操作,负责数据块的创建、删除和复制。
1.3.5、Secondary NameNode
Secondary NameNode并不是NameNode的热备份,而是辅助NameNode进行元数据管理的节点。它定期获取NameNode的元数据快照并合并编辑日志,以减轻NameNode的负载。
1.3.6、Secondary NameNode的职责
- 元数据快照:定期从NameNode获取元数据快照。
- 合并编辑日志:将元数据快照与编辑日志合并,生成新的元数据文件,减轻NameNode的内存压力。
2、HDFS的工作原理
HDFS通过分布式存储和冗余机制,实现高可靠性和高可用性。以下是HDFS的几个关键工作原理。
2.1、文件存储
HDFS将文件分割成固定大小的块(3.x默认为128MB),并将这些块存储在不同的DataNode上。每个块会被复制到多个DataNode(默认3个副本),以确保数据的可靠性。
2.2 、数据写入
当客户端向HDFS写入数据时,数据首先被分割成块,并通过Pipeline机制写入到多个DataNode。具体步骤如下:
- 客户端请求NameNode:客户端向NameNode请求写入文件。
- NameNode分配块和DataNode:NameNode为文件分配数据块并选择存储这些块的DataNode。
- 客户端写入数据块:客户端将数据块写入第一个DataNode,第一个DataNode再将数据块复制到第二个DataNode,依此类推。
- 数据块确认:当所有副本写入成功后,客户端接收到确认消息,表示数据写入完成。
2.3、 数据读取
当客户端从HDFS读取数据时,NameNode提供数据块的位置信息,客户端直接从相应的DataNode读取数据。具体步骤如下:
- 客户端请求NameNode:客户端向NameNode请求读取文件。
- NameNode返回块位置:NameNode返回文件块所在的DataNode列表。
- 客户端读取数据块:客户端直接从DataNode读取数据块,并在本地合并这些数据块,恢复成完整的文件。
2.4、 容错机制
HDFS通过数据块副本机制实现容错。当DataNode发生故障时,NameNode会检测到该DataNode的心跳信号丢失,并在其他健康的DataNode上重新复制丢失的数据块。
2.5、元数据管理
NameNode负责管理文件系统的元数据,包括文件名、目录结构、权限和数据块位置等。为了保证元数据的一致性和持久性,NameNode将元数据存储在内存中,并定期写入到本地磁盘。
3、HDFS的Shell操作
hadoop fs 具体命令 OR hdfs dfs 具体命令
#从本地粘贴到HDFS
hadoop fs -copyFromLocal a.txt /demo
hadoop fs -put a.txt /
#-rm -r:递归删除目录及目录里面内容;-rm:删除文件或文件夹
hadoop fs -rm -r /demo/a.txt
#-moveFromLocal:从本地剪切粘贴到HDFS
hadoop fs -moveFromLocal a.txt /demo
#-appendToFile:追加一个文件到已经存在的文件末尾
hadoop fs -appendToFile b.txt /demo/a.txt
#-copyToLocal:从HDFS拷贝到本地
hadoop fs -copyToLocal /demo/a.txt /usr/local/hadoop-3.4.0
hadoop fs -get /demo/a.txt /usr/local/hadoop-3.4.0
#显示目录
hadoop fs -ls /demo
#查看内容
hadoop fs -cat /demo/a.txt
#创建路径
hadoop fs -mkdir /demo
#复制
hadoop fs -cp /a.txt /demo/
#-tail:显示一个文件的末尾1kb的数据
hadoop fs -tail /demo/a.txt
#查看大小
hadoop fs -du -h /demo
#-setrep:设置HDFS中文件的副本数量,副本数超过DataNode时,并不会创建那么多副本,只有当有足够的节点数时才会创建
hadoop fs -setrep 2 /demo/a.txt
4、HDFS的API操作
4.1、配置客户端环境变量
配置环境变量
配置path变量
重启电脑使变量生效
4.2、客户端api的使用
package com.xiaojie.hadoop.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
@Component
@Slf4j
public class HdfsClientUtil {
@Value("${wssnail.hdfs.url}")
private String url;
@Value("${wssnail.hdfs.user-name}")
private String userName;
@Autowired
private Configuration configuration;
//创建文件
public void mkDirs() throws URISyntaxException, IOException, InterruptedException {
//获取文件系统
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 创建目录
fs.mkdirs(new Path("/hello/world"));
// 3 关闭资源
fs.close();
log.info("创建目录成功>>>>>>>>>>>>>>>");
}
//上传文件
public void putFile() throws URISyntaxException, IOException, InterruptedException {
//设置副本数
configuration.set("dfs.replication", "2");
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 上传文件
fs.copyFromLocalFile(new Path("d:/hello.txt"), new Path("/"));
// 3 关闭资源
fs.close();
}
//下载文件
public void downloadFile() throws URISyntaxException, IOException, InterruptedException {
// 1 获取文件系统
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 执行下载操作
// boolean delSrc 指是否将原文件删除
// Path src 指要下载的文件路径
// Path dst 指将文件下载到的路径
// boolean useRawLocalFileSystem 是否开启文件校验
fs.copyToLocalFile(false, new Path("/hello.txt"), new Path("d:/hello1.txt"), true);
// 3 关闭资源
fs.close();
}
//移动
public void renameFile() throws URISyntaxException, IOException, InterruptedException {
// 1 获取文件系统
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 修改文件名称
fs.rename(new Path("/hello.txt"), new Path("/hello1.txt"));
// 3 关闭资源
fs.close();
}
//删除
public void deleteFile() throws URISyntaxException, IOException, InterruptedException {
// 1 获取文件系统
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 删除
fs.delete(new Path("/hello1.txt"), true);
// 3 关闭资源
fs.close();
}
//查看
public void listFiles() throws URISyntaxException, IOException, InterruptedException {
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.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("文件修改时间:" + simpleDateFormat.format(fileStatus.getModificationTime()));
System.out.println("副本数:" + fileStatus.getReplication());
System.out.println("blockSize: " + fileStatus.getBlockSize() / 1024 / 1024 + "M");
System.out.println("文件名称信息:" + fileStatus.getPath().getName());
// 获取块信息
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
System.out.println("块信息:" + Arrays.toString(blockLocations));
}
// 3 关闭资源
fs.close();
}
//文件文件夹判断
public void isFile() throws URISyntaxException, IOException, InterruptedException {
FileSystem fs = FileSystem.get(new URI(url), configuration, userName);
// 2 判断是文件还是文件夹
FileStatus[] listStatus = fs.listStatus(new Path("/"));
for (FileStatus fileStatus : listStatus) {
// 如果是文件
if (fileStatus.isFile()) {
System.out.println("文件名称:" + fileStatus.getPath().getName());
} else {
System.out.println("目录名称:" + fileStatus.getPath().getName());
}
}
// 3 关闭资源
fs.close();
}
}
完整代码:见附录
5、参考
https://blog.csdn.net/weixin_42175752/article/details/140097992
6、附录
1、window环境下的hadoop依赖
链接: https://pan.baidu.com/s/1nFIMXRlVpOrt5ahenq_Prg?pwd=c23a
2、完整代码
https://gitee.com/whisperofjune/spring-boot.git