HDFS产出背景及定义
随着数据量的越来越大,在一个操作系统存不下所有的数据,那么就分配更多的操作系统管理的磁盘中,但是不大方便维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件系统的。HDFS只是分布式文件系统中的一种。
HDFS是一个文件系统,用于存储文件,通过目录来定位文件。其次是分布式的,由很多台服务器联合起来实现功能,集群中的服务器有各自的角色。
HDFS的使用场景:适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘。
优缺点
- 优点
- 高容错性,数据自动保存多个副本,是通过增加副本形式,提高容错性。某一个副本丢失时候,会自动恢复
- 适合处理大数据,能够存取大规模的数据。存取大规模的文件,可在廉价的机器上通过多个副本机制,提高可靠性
- 缺点
- 不适合低延时的数据访问,比如毫秒级别的存储数据,是做不到的
- 无法高效的对大量小文件进行存储
- 不支持并发写入,文件随机修改
HDFS的Shell操作
bin/hadoop fs 具体命令
OR bin/hdfs dfs 具体命令
两个是完全相同的
从本地文件上传到HDFS的命令
- put,复制
hadoop fs -put NOTICE.txt /
- copyFromLocal,和put基本一样,多了一个多线程拷贝的功能
hadoop fs -copyFromLocal README.txt /
- moveFromLocal,剪切
hadoop fs -moveFromLocal README.txt /
- appendToFile,追加一个文件到另一个文件
hadoop fs -appendToFile NOTICE.txt /README.txt
将NOTICE.txt追加到根目录下的README.txt
从HDFS到本地
- get,下载
hadoop fs -get /README.txt .
,下载到当前目录
- getmerge,合并下载,可以批量下载文件
hadoop fs -getmerge /*.txt 1.txt
将hdfs根目录下的所有文件,下载到1.txt中
- copyToLocal,也是下载,和get完全一样
HDFS客户端操作
创建一个Maven工程hdfs01,并导入相应的依赖坐标+日志添加
<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>
创建测试类
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
/**
* @author fangxi created by 2020/9/6
*/
public class HdfsTest {
private FileSystem fileSystem;
@Before
public void create() throws IOException, InterruptedException {
this.fileSystem = FileSystem.get(URI.create("hdfs://10.211.55.40:8020"), new Configuration(), "fangxi");
}
@After
public void close() throws IOException {
this.fileSystem.close();
}
/**
* 上传
* @throws IOException
*/
@Test
public void upload() throws IOException {
Path src = new Path("/Users/fangxi/Java/workspace/bigdata/hdfs01/src/test/java/com/storyhasyou/hdfs/HdfsTest.java");
// 第一个参数是否删除源文件,第二个是源文件地址,第三个目标地址
fileSystem.copyFromLocalFile(false, src, new Path("/"));
}
/**
* 下载
* @throws IOException
*/
@Test
public void download() throws IOException {
fileSystem.copyToLocalFile(new Path("/README.txt"), new Path("/Users/fangxi/Java/workspace/bigdata/hdfs01"));
}
/**
* 追加
*/
@Test
public void append() throws IOException {
FSDataOutputStream outputStream = fileSystem.append(new Path("/README.txt"));
outputStream.write("www.storyhasyou.top".getBytes());
IOUtils.closeStream(fileSystem);
}
/**
* 查看文件或文件夹
* @throws IOException
*/
@Test
public void ls() throws IOException {
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
Arrays.stream(fileStatuses).forEach(System.out::println);
}
/**
* 移动或者重命名
* @throws IOException
*/
@Test
public void mv() throws IOException {
fileSystem.rename(new Path("/README.txt"), new Path("/abc.txt"));
}
}
HDFS的数据流
HDFS写数据流程
- 客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是否已存在,父目录是否存在。
- NameNode返回是否可以上传。
- 客户端请求第一个 Block上传到哪几个DataNode服务器上。
- NameNode返回3个DataNode节点,分别为dn1、dn2、dn3。
- 客户端通过FSDataOutputStream模块请求dn1上传数据,dn1收到请求会继续调用dn2,然后dn2调用dn3,将这个通信管道建立完成。
- dn1、dn2、dn3逐级应答客户端。
- 客户端开始往dn1上传第一个Block(先从磁盘读取数据放到一个本地内存缓存),以Packet为单位,dn1收到一个Packet就会传给dn2,dn2传给dn3;dn1每传一个packet会放入一个应答队列等待应答。
- 当一个Block传输完成之后,客户端再次请求NameNode上传第二个Block的服务器。(重复执行3-7步)
HDFS读数据流程
客户端通过Distributed FileSystem向NameNode请求下载文件,NameNode通过查询元数据,找到文件块所在的DataNode地址
挑选一台DataNode(就近原则,然后随机)服务器,请求读取数据。
DataNode开始传输数据给客户端(从磁盘里面读取数据输入流,以Packet为单位来做校验)。
客户端以Packet为单位接收,先在本地缓存,然后写入目标文件。