HDFS架构设计
HDFS是什么
HDFS(Hadoop Distributed File System)Hadoop分布式文件系统
由论文为 GFS(Google File System)Google 文件系统启发,是 Google GFS 的开源 Java 实现。
HDFS组件角色
- NameNode HDFS元数据管理者- DateNode 文件系统的工作节点- Client 代表用户与NameNode或者DateNode交互来访问整个文件系统的对象
HDFS的基本架构

HDFS 是一个主从式(Master/Slave)的体系结构。HDFS 集群中有一个 NameNode 和一些 DataNodes,
NameNode 管理文件的元数据,DataNode 存储实际的数据。从用户的角度看,就像操作传统的文件系
统一样,可以通过目录路径对文件执行创建、读取、删除操作。客户端联系 NameNode 来获取元数据
信息,而真正的文件 I/O 是直接和 DataNode 进行交互的。
读文件流程

详细步骤:
第一步:Client 向 NameNode 发送数据请求后,寻找数据对应的数据块的位置信息。
第二步:NameNode 返回文件对应的数据块元数据信息,如所属机器、数据块的 block_id、数据
块的先后顺序等。
第三步:由 Client 与 DataNode 直接通信,读取各个 block 数据块的信息。过程为并行读取,
由客户端合并数据。
写文件流程

详细步骤:
第一步:
Client 向 NameNode 发送写数据请求后,寻找可以写入的数据块 block 信息的机器位置。
若文件过大,写入可能会分成很多 block 数据块,实际上是通过一个 block 一个 block的申请。
若副本为 3,则每次请求后返回一个 block 的对应的 3 个副本的 block 的存放位置。
第二步:
Client 获取到对应的 block 数据块所处的 DataNode 节点位置后,Client 开始写操作。
Client 先写入第一个 DataNode,以数据包 package 的方式逐个发送和接收。如 64K 大小的 package 包大小来发送和接收。
存在多个副本时,package 包的写入是依次进行的。写入到第一个 DataNode 后,第一个 向第二个 DataNode 传输。第二个写完后,由第二个向第三个 DataNode 传输 package。 以此类推。
写完一个 block 数据块后,如果还有则反复进行第一步和第二步。
第三步:
待所有的数据块 block 均写完后,Client 接收到全部写完的 ack 答复,告诉 NameNode 数据已写完,Client 关闭 socket 流。
DataNode 也会向 NameNode 报告新增 block 数据块的信息。
HDFS高可靠性措施
冗余备份,跨机架副本存放,心跳检测,数据完整性检查,安全模式,核心文件备份,空间回收
HDFS Shell应用

常用的shell命令
所有命令
- 查看 hdfs 根目录下的文件列表: hdfs dfs -ls /
- 查看 hdfs 的某个文本文件: hdfs dfs -cat /tmp/index.html
- 在 hdfs 中创建/tmp/tianliangedu 目录: hdfs dfs – mkdir /tmp/tianliangedu
- 删除/tmp/tianliangedu 目录: hdfs dfs -rmr /tmp/tianliangedu
- 将 hdfs 中的/tmp/index.html 文件下载到本地文件的当前路径下: hdfs dfs -copyToLocal /tmp/index.html .
- 从本地当前目录下,上传之前的 index.html 文件到 hdfs 的/tmp/tianliangedu 目录中: hdfs dfs -copyFromLocal index.html /tmp/tianliangedu
- 查看压缩文本文件的格式: hdfs dfs -text /tmp/tianliangedu/index.html.gz | more
- 查看 hdfs 中目录/tmp/tianliangedu 中文件占用磁盘大小: hdfs dfs -du -h /tmp/tianliangedu
- 在/tmp/tianliangedu 目录中创建空文件 HelloWorld.txt: hdfs dfs -touchz /tmp/tianliangedu/HelloWorld.txt
- 查看 hdfs dfs 中某个命令的用法,比如:cp: hdfs dfs -usage cp
HDFS Java API的应用
操作实现
- 资源准备- Maven环境搭建- Pom配置依赖
<projectxmlns="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.0http://maven.apache.org/xsd/maven-4.0.0.xsd";><modelVersion>4.0.0</modelVersion><groupId>com.tianliangedu.course</groupId><artifactId>TlHadoopCore</artifactId><version>0.0.1-SNAPSHOT</version><!-- 首先配置仓库的服务器位置,首选阿里云,也可以配置镜像方式,效果雷同 --><repositories><repository><id>nexus-aliyun</id><name>Nexus aliyun</name><url>http://maven.aliyun.com/nexus/content/groups/public</url></repository></repositories><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>TlHadoopCore</finalName><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.7</source><target>1.7</target><encoding>UTF-8</encoding></configuration></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>assembly</goal></goals></execution></executions></plugin></plugins></build></project>
- 编码实现 具体代码实现(例)
//新建源码包 com.tianliangedu.utils,并在其中新建 java 文件 HdfsFileOperatorUtil.java。//代码如下:package com.tianliangedu.utils;import java.io.ByteArrayOutputStream;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 org.apache.log4j.Logger;/*** hdfs 文件操作工具类,从任意的 hdfs filepath 中读取文本内容*/public class HdfsFileOperatorUtil {//添加日志输出能力Logger logger = Logger.getLogger(HdfsFileOperatorUtil.class);// 加载配置文件到内存对象static Configuration hadoopConf = new Configuration();/** 从 HDFS 上读取文件 */public static String readFromFile(String srcFile) throws Exception {//文件路径的空判断if (srcFile == null || srcFile.trim().length() == 0) {throw new Exception("所要读取的源文件" + srcFile + ",不存在,请检查!");}//将文件内容转换成字节数组byte[] byteArray = readFromFileToByteArray(srcFile);if (byteArray == null || byteArray.length == 0) {return null;}//将 utf-8 编码的字节数组通过 utf-8 再进行解码return new String(byteArray, "utf-8");}/*** 将指定的文件路径从 hdfs 读取并转换为 byte array.** @param srcFile* @return*/public static byte[] readFromFileToByteArray(String srcFile)throws Exception {if (srcFile == null || srcFile.trim().length() == 0) {throw new Exception("所要读取的源文件" + srcFile + ",不存在,请检查!");}//获取 hadoopConf 对应的 hdfs 集群的对象引用FileSystem fs = FileSystem.get(hadoopConf);//将给定的 srcFile 构建成一个 hdfs 的路径对象 PathPath hdfsPath=new Path(srcFile);FSDataInputStream hdfsInStream = fs.open(hdfsPath);//初始化一块字节数组缓冲区,大小为 65536。缓存每次从流中读取出来的字节数组byte[] byteArray = new byte[65536];//初始化字节数输出流, 存放最后的所有字节数组ByteArrayOutputStream bos = new ByteArrayOutputStream();// 实际读过来多少int readLen = 0;//只要还有流数据能读出来,就一直读下去while ((readLen = hdfsInStream.read(byteArray)) > 0) {bos.write(byteArray);byteArray = new byte[65536];}//读取完成,将 hdfs 输入流关闭hdfsInStream.close();//将之前写到字节输出流中的字节,转换成一个整体的字节数组byte[] resultByteArray=bos.toByteArray();bos.close();return resultByteArray;}public static void main(String[] args) throws Exception {//定义要读入的 hdfs 的文件路径String hdfsFilePath = "/tmp/tianliangedu/input.txt";//将文件从 hdfs 读取下来,转化成字符串String result = readFromFile(hdfsFilePath);//根据题意,将字符串通过命令行输出System.out.println(result);} }
经典问题分析
HDFS 为何要将文件分成 block 块存储?
- 减少底层操作系统的 IO 读取时的寻址时间
- 方便更高效的流式读取,提高吞吐量
HDFS block 块的默认大小时多少?
- dfs.blocksize 为 Hadoop 定义 block 块大小的设置参数,在 hdfs-site.xml 中
- 版本不一样,默认值不同。Hadoop2.2.x 及以后版本均为 128M
HDFS block 块的大小是否可以更改?
- 可以修改
- 参数修改对以前的文件不起作用,对以后的文件起作用
- 也可针对上传文件临时修改,指定-D dfs.blocksize 即可
一个 block 块文件是否可以存储多个文件数据?
- 一个 block 块文件不会跨文件存储
- 一个 block 块文件最多只会存储一个文件对应的数据
如果一个文件的大小,小于一个 blocksize,那么它实际占用多大空间?
- 实际文件多大则占多大空间,但是占了一个 block 块的元数据空间大小
- 小文件越多,Hadoop NameNode 的压力越大。故 Hadoop 的优势在于处理大文件数据,GB、 TB 甚至 PB 等。
HDFS block 越大越好?还是越小越好?
- 越大则分块越少,则 NameNode 压力将减小,但并行的 IO 和处理能力降低
- 越小则分块越多,则 NameNode 处理压力越大,但因为寻址时间太久,不利于提高吞吐量
- 适中即可,一般采用官方的 128M 即可
