前言
本文主要介绍了 HDFS 的体系架构以及其执行流程,并给出了读写操作的编程实例,希望对 HDFS 有个初步的认识。
简介
HDFS (Hadoop Distributed File System) 是一个运行在商业 PC 上的分布式文件系统,其设计思想源自于 Google 2003 年发布的论文 The Google File System 。HDFS的主要目的是为了解决大规模数据存储和管理的问题。
体系架构
上图表明 HDFS 是一个标准的 master/slave 架构,主要由三个部分构成:
- NameNode(master 节点)
- 元数据(MetaData)的管理,其中元数据由文件路径名、数据块ID以及存储位置等信息构成
- 管理 HDFS 的名字空间。
- SecondaryNameNode
- 定期合并 NameNode 的 edit logs(对文件系统的改动序列) 到 fsimage(对整个文件系统的快照),并拷贝修改后的 fsimage 到 NameNode。
- 提供一个 NameNode 的检查点(切忌认为是 NameNode 的备份),可用于 NameNode 的故障恢复。
- DataNode(slave 节点)
- 提供文件存储和进行数据块操作。
- 周期性的向 NameNode 汇报块信息。
这里对图中出现的一些概念进行说明:
-
Replication(副本)
为了保证数据的高可用,HDFS 会对写入的数据进行冗余存储,默认情况下会保存 3 份。
-
Blocks
Block 是最基本的存储和操作单位(默认情况下为 128M),这里的 Block 不是指物理 Block ,而是指文件系统的 Block,其大小一般是物理 Block 的整数倍。
执行流程
读文件
读文件的过程可以概括为:
- Client 向 NameNode 发起请求获取文件数据块位置信息
- Client 按照数据块距 Client 的远近依次进行连接然后读取数据
写文件
写文件的过程可以概括为:
- Client 向 NameNode 发起写文件的请求获得可写的 DataNode 列表等信息
- Client 根据 HDFS 设定的分块大小对文件进行分块
- Client 和 NameNode 分配的 DataNode 构成 pipeline 并进行数据写入
- 写入完成之后,NameNode 接收来自 DataNode 的消息进行元数据的更新
常用命令
文件操作
-
列出文件
hdfs dfs -ls <path> 复制代码
-
创建目录
hdfs dfs -mkdir <path> 复制代码
-
上传文件
hdfs dfs -put <localsrc> <dst> 复制代码
-
输出文件内容
hdfs dfs -cat <src> 复制代码
-
文件复制到本地
hdfs dfs -get <src> <localdst> 复制代码
-
删除文件和目录
hdfs dfs -rm <src> hdfs dfs -rmdir <dir> 复制代码
管理
-
查看统计信息
hdfs dfsadmin -report 复制代码
-
进入和退出安全模式(该模式不允许文件系统有任何修改)
hdfs dfsadmin -safemode enter hdfs dfsadmin -safemode leave 复制代码
编程实例
-
IDEA 新建 Maven 项目
勾选相关选项后,点击 next 填入项目相关信息即可
-
pom.xml 中添加依赖
<dependencies> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>2.9.2</version> //根据 Hadoop 版本进行选择 </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-client</artifactId> <version>2.9.2</version> </dependency> </dependencies> 复制代码
-
读写文件
创建 Sample 类编写相应的读写函数
-
Sample 类
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataInputStream; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import java.io.*; /** * @author ikroal */ public class Sample { //默认的 HDFS 地址 private static final String DEFAULT_FS = "hdfs://localhost:9000"; private static final String PATH = DEFAULT_FS + "/tmp/demo.txt"; private static final String DEFAULT_FILE = "demo.txt"; public static void main(String[] args) { Configuration conf = new Configuration(); FileSystem fs = null; conf.set("fs.defaultFS", DEFAULT_FS); //配置 HDFS 地址 try { fs = FileSystem.get(conf); write(fs, DEFAULT_FILE, PATH); read(fs, PATH); } catch (IOException e) { e.printStackTrace(); } finally { try { if (fs != null) { fs.close(); } } catch (IOException e) { e.printStackTrace(); } } } } 复制代码
-
write 函数
/** * 进行文件写入 * @param inputPath 待写入文件路径 * @param outPath HDFS 的写入路径 */ public static void write(FileSystem fileSystem, String inputPath, String outPath) { FSDataOutputStream outputStream = null; FileInputStream inputStream = null; try { outputStream = fileSystem.create(new Path(outPath)); //获得 HDFS 的写入流 inputStream = new FileInputStream(inputPath); //读取本地文件 int data; while ((data = inputStream.read()) != -1) { //写入操作 outputStream.write(data); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } } 复制代码
-
read 函数
/** * 进行文件读取 * @param path HDFS 上待读取文件路径 */ public static void read(FileSystem fileSystem, String path) { FSDataInputStream inputStream = null; BufferedReader reader = null; try { inputStream = fileSystem.open(new Path(path)); //获取 HDFS 读取流 reader = new BufferedReader(new InputStreamReader(inputStream)); String content; while ((content = reader.readLine()) != null) { //读取并输出到控制台 System.out.println(content); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (inputStream != null) { inputStream.close(); } if (reader != null) { reader.close(); } } catch (IOException e) { e.printStackTrace(); } } } 复制代码
-
-
在工程文件夹的根目录下创建计划上传的文件(这里是 demo.txt),填入 Hello World!
-
启动 Hadoop 然后运行程序查看结果
通过 http://localhost:50070/explorer.html#/ 可以查看写入结果
控制台则会输出上传文件的内容