一.特点
- 高容错和高可用性
- 流式数据访问
- 弹性存储,支持大规模数据集
- 简答一致性模型(一次写,多次读)
- 移动计算而非移动数据
- 协议和接口多样
- 多样的数据管理功能
二.架构设计
2.1核心组件
- NameNode(NN)
- 元数据管理者,管理NameSpace(文件系统命名空间)记录文件是如何切分并存储在那些节点上的一些信息
- NameSpace上任何属性的更改都由NameNode记录,维护整个系统的文件和目录.
- DataNode(DN)
- DN是文件系统的工作节点,根据客户端或者NameNode发送的管理指令,执行对应的读写操作
- 通过心跳检测机制定期向NameNode发送自身存储块的信息
- Client
- Client代表用户与NN或者DN进行交互
- 用户面向Client 的API编程
2.2架构图
三.读文件写文件流程
3.1读文件流程
客户端首先向NameNode发起读文件请求
NN将该文件的分块信息,存储位置信息返回给客户端
客户端依据NN返回来的元数据向DataNode并行读取文件
3.2写文件流程
- 第一步:客户端向NN发起写文件请求,NN检测可写的节点信息,如果文件较大进行分块处理(客户端申请的时候是一个块一个块的申请),比如有三个副本,每次NN只返回一个block块的三个副本位置信息.
- 第二步:客户端获取到对应block块所处的DN节点位置后,客户端开始写操作,首先向第一个DN写,以数据包的形式发送,存在多个副本的时候,包的写入是依次进行的,写入第一个DN后,第一个DN会向第二个DN写数据依次进行,写完第一个block后,再重复进行第一步和第二步
- 第三步:等待所有的块写完后,客户端接收到全部写完的ack回复,然后关闭socket流.DN向NN报告新增的block块信息.
四.HDFS高可用性的措施
- 冗余备份
- 核心文件备份
- 跨机架存储
- 心跳检测机制
- 安全模式
- 数据完整性校验
- 空间回收(防止误删)
五.常用的HDFS命令
5.1分类
5.2文件系统操作命令
以下命令都以hdfs dfs 开头
5.3文件系统管理命令
以下均以hdfs dfsadmin开头
六.HDFS javaAPI的应用
6.1.Demo开发流程
- 要求:需要使用java读取hdfs的一个文本文件,并将其内容打印在出来
- 环境准备
- maven环境准备
- 引入hdfs依赖
- 打包配置:配置主类
- maven环境准备
- 环境准备
- 代码编写
- 定义路径
- 读取文件并返回一个字符串
- 创建配置类对象Configuration conf
- 创建文件操作对象FileSystem fs = FileSystem.open(conf)
- 获取文件输入流 fs.open(new Path(路径))
- 将输入流转换成字节数组输出流
- 将字节数组输出流转换成字符串
- 打印到控制台
- 上线测试
6.2代码实现
pom配置文件
<?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.fjh</groupId>
<artifactId>readFromHDFS</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 引入 hadoop-cli-2.7.4 依赖 -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>HDFSUtil</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.fjh.Main</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
java代码
package com.fjh.util;
import com.fjh.config.Config;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* @author Antg
* @date 2021/9/26 16:01
*/
public class ReadUtil {
public static String readWithPath(String path) throws Exception {
//非空校验
if(path==null||path.trim().length()==0){
throw new Exception("路径不能为空");
}
//获取hdfs的输入流
byte[] context = getInputStreamFromHDFSWithPath(path);
//返回字符串
return new String(context, StandardCharsets.UTF_8);
}
//获取hdfs的文件输入流
public static byte[] getInputStreamFromHDFSWithPath(String path) throws Exception {
//非空校验
if(path==null||path.trim().length()==0){
throw new Exception("路径不能为空");
}
//通过配置对象创建文件操作系统
FileSystem fs = FileSystem.get(Config.conf);
//创建HDFS文件路径
Path file = new Path(path);
//获取流
FSDataInputStream inputStream = fs.open(file);
//将流转换成字节数组
//创建一个缓存流
byte[] buf = new byte[10*1024];
//每次读取的长度
int readLength = 0;
//输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//开始读取流到输出流
while((readLength=inputStream.read(buf))>0){
//读多少写多少,防止多写
bos.write(buf,0,readLength);
}
inputStream.close();
bos.close();
return bos.toByteArray();
}
}