文章目录
1、HDFS概述
1.1 HDFS的意义
HDFS即Hadoop Distributed File System,是一种分布式文件系统,用于解决大数据的存储问题。
1.2 HDFS的使用场景
适合一次写入,多次读出。
1.3 HDFS的优缺点
优点:
- 高容错
- 通过副本,提高容错性
- 副本丢失,自动恢复
- 适合处理大数据
- 单个文件的数据规模大小
- 文件数量规模
- 构建在廉价的机器上,通过副本机制,提高可靠性、扩展性
缺点:
-
不适合低延迟数据访问
这主要受数据传输的带宽和数据校验影响,需要消耗大量时间
-
无法高效的对小文件进行存储
一方面,元数据加载于NameNode节点的内存中。无论数据块的大小都会对应一个元数据,因此能存大的,不存小的;
另一方面,存储过多的小文件会导致寻址时间超过读取时间,违反HDFS设计目标。
-
不支持并发写入、文件随机修改。
不允许多个线程同时写;
仅支持追加,不支持随机修改;
1.4 HDFS组成架构
-
NameNode:主节点
- 管理HDFS的名称空间NameSpace;在NameNode中的Namespace管理层是负责管理整个HDFS集群文件系统的目录树以及文件与数据块的映射关系。
- 配置副本策略;
- 管理数据块的映射信息;
- 处理客户端读写请求。
-
DataNode:实际存储数据的节点
- 存储实际的数据块;
- 执行数据块的读/写操作。
-
Client
- 文件切分;
- 与NameNode交互
- 与DataNode交互
- Client提供一些命令管理HDFS
- Client提供一些命令操作HDFS,如增删改查。
-
SecondaryNameNode:并非热备。
- 辅助NameNode,分担其工作量;定期合并Fsimage和Edits,并推送给NameNode;
- 在紧急情况下,可辅助恢复NameNode。
1.5 HDFS块大小
寻址时间为传输时间的1%最佳。如果寻址时间为10ms,那么传输所耗时间为1s最佳;而目前磁盘的速率普遍为100MB/s。因此规定块大小为128M。
- 块设置太小,会导致寻址时间增加,寻址时间占比过高;
- 块设置太大,导致磁盘传输数据的效率低下;
另外,Map任务数太少,作业执行速度变慢。
总结:HDFS块大小设置主要取决于磁盘传输速率。
2、HDFS的API操作
2.1 基础环境
-
配置Hadoop3.1.0环境变量;
-
导入依赖
<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>
-
在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
2.2 实操代码
无论什么客户端代码,例如jdbc hdfs kafka zookeeper;
- 1.创建客户端对象
- 2.使用客户端对象进行操作
- 3.关闭客户端对象
package com.hpu.hadoop.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class HDFSClient {
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
//1.创建客户端对象
Configuration configuration = new Configuration();
URI uri = new URI("hdfs://hadoop102:8020");
// URI uri = URI.create("hdfs://hadoop102:8020");
FileSystem fileSystem = FileSystem.get(uri, configuration, "hadoop");
//2.使用客户端对象进行操作
fileSystem.mkdirs(new Path("/test"));
//3.关闭客户端对象
fileSystem.close();
}
}
package com.hpu.hadoop.hdfs;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
public class HDFS_Test {
private FileSystem fileSystem;
private Configuration configuration;
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
configuration = new Configuration();
configuration.set("dfs.replication","2");
fileSystem = FileSystem.get(new URI("hdfs://hadoop102:8020"), configuration, "hadoop");
}
@After
public void close() throws IOException {
fileSystem.close();
}
@Test
public void mkdir() throws IOException {
fileSystem.mkdirs(new Path("/zyn/mkdirtest"));
}
@Test
public void put() throws IOException {
/**
* 参数解读
* boolean delSrc 是否删除源文件 windows本地
* boolean overwrite 是否覆盖目标文件 hdfs
* Path src 上传的文件路径 windows
* Path dst 存放的文件路径 hdfs
*/
fileSystem.copyFromLocalFile(false,true,new Path("E:\\smc.zip"),new Path("/zyn/mkdirtest/"));
}
@Test
public void get() throws IOException {
/**
* 参数解读
* 1.boolean delSrc 是否删除源文件
* 2.Path src 源文件路径
* 3.Path dst 目标文件路径
* 4.boolean useRawLocalFileSystem 是否校验 true 不校验 false 校验
*/
fileSystem.copyToLocalFile(false,new Path("/zyn/mkdirtest/smc.zip"),new Path("E:\\AAA\\a.zip"),true);
}
@Test
public void mv() throws IOException {
//文件的更名
//fs.rename(new Path("/java/word.txt"),new Path("/java/1.txt"));
//文件的移动
//fs.rename(new Path("/java/1.txt"),new Path("/input"));
//文件的更名且移动
//fs.rename(new Path("/input/1.txt"),new Path("/java/word.txt"));
//目录的更名
//fs.rename(new Path("/java"),new Path("/linux"));
//目录的移动
//fs.rename(new Path("/linux"),new Path("/input"));
//目录的更名且移动
fileSystem.rename(new Path("/zyn/mkdirtest/1.zip"),new Path("/zyn/test/smc.zip"));
}
@Test
public void rm() throws IOException {
fileSystem.delete(new Path("/zyn"),true);
}
//查看文件的详情信息
@Test
public void ls() throws IOException {
RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true);
while (listFiles.hasNext()) {
LocatedFileStatus fileStatus = listFiles.next();
System.out.println("------------"+fileStatus.getPath().getName()+"------------");
// Permission Owner Group Size Last Modified Replication Block Size Name
System.out.println(fileStatus.getPermission());
System.out.println(fileStatus.getOwner());
System.out.println(fileStatus.getGroup());
System.out.println(fileStatus.getLen());
long time = fileStatus.getModificationTime();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
System.out.println(format.format(time));
System.out.println(fileStatus.getReplication());
System.out.println(fileStatus.getBlockSize());
BlockLocation[] blockLocations = fileStatus.getBlockLocations();
System.out.println(Arrays.toString(blockLocations));
}
}
@Test
public void fileOrDir() throws IOException {
FileStatus[] listStatus = fileSystem.listStatus(new Path("/"));
for (FileStatus status : listStatus) {
if (status.isFile()){
System.out.println("f--"+status.getPath());
} else if (status.isDirectory()){
System.out.println("d--"+status.getPath());
}
}
}
public void fileOrDirRecursive(Path path) throws IOException {
FileStatus[] listStatus = fileSystem.listStatus(path);
for (FileStatus status : listStatus) {
if (status.isFile()){
System.out.println("f--"+status.getPath());
} else if (status.isDirectory()){
Path path1 = status.getPath();
System.out.println("d--"+path1);
fileOrDirRecursive(path1);
}
}
}
@Test
public void testFDR() throws IOException {
fileOrDirRecursive(new Path("/"));
}
//手动上传
@Test
public void putByIo() throws IOException {
//1.输入流
FileInputStream inputStream = new FileInputStream("E:\\smc.zip");
//2.输出流
FSDataOutputStream outputStream = fileSystem.create(new Path("/zy/smc.zip"));
IOUtils.copyBytes(inputStream, outputStream,configuration);
IOUtils.closeStreams(outputStream,inputStream);
}
@Test
public void getByIo() throws IOException {
//1.输入流
FSDataInputStream inputStream = fileSystem.open(new Path("/zyn"));
//2.输出流
FileOutputStream fileOutputStream = new FileOutputStream("E:\\1.zip");
//3.对拷
IOUtils.copyBytes(inputStream,fileOutputStream,configuration);
//4.关闭资源
IOUtils.closeStreams(fileOutputStream,inputStream);
}
}
注意事项:
参数优先级排序:(1)客户端代码中设置的值 >(2)ClassPath下的用户自定义配置文件 >(3)然后是服务器的自定义配置(xxx-site.xml) >(4)服务器的默认配置(xxx-default.xml)