暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

分布式文件系统HDFS

MixDream 2022-05-17
185

1、产生背景
 传统的本地文件系统(单机式),在数据量增长过快、数据备份、数据安全性、操作使用便捷性上存在严重不足。
2、特点介绍
  • 高容错高可用性硬件错误是常态而不是异常

HDFS设计运行在普通硬件上,所以硬件故障是很正常的。HDFS提供文件存储副本策略,可以实现错误自检并快速自动恢复。个别硬件的损坏不影响整体数据完整性和计算任务的正常执行。

  • 流式数据访问

HDFS主要采用流式数据读取,做批量处理而不是用户交互处理,因此HDFS更关注数据访问的高吞吐量
  • 弹性存储,支持大规模数据集

HDFS支持大文件存储,典型的文件在GB甚至TB级别,可以支持数以千万计的大规模数据集。根据业务需要灵活地增加或者缩减存储节点弹性存储的最大挑战是减小在修改存储节点时的数据震荡问题。
  • 简单一致性模型

HDFS文件实行一次性写、多次读的访问模式。设计为文件一经创建、写入和关闭之后就不需要再更改了,这种设计和假定简化了数据一致性问题,使高吞吐量成为可能。
  • 移动计算而非移动数据

由于HDFS支持大文件存储,对于大文件来说,移动计算比移动数据的代价要低。这样也可以减少网络的拥塞和提高系统的吞吐量。
  • 协议和接口多样性

为上层应用提供了多种接口,Http RestFul接口、NFS接口、Ftp接口等等POSIX标准协议,另外通常会有自己的专用接口。
  • 多样的数据管理功能

对于数据压缩、数据加密、数据缓存存储配额等提供了多样的管理功能。
3、应用场景
  • 各大运营商

  • 中大型互联网公司,如BAT、京东、乐视、美团等

  • 金融银行保险类公司

  • 各大云平台底层存储平台

  • 其他本地系统无法承载存储能力的应用



HDFS架构设计

1、HDFS是什么
 HDFS(Hadoop Distributed File System )Hadoop分布式文件系统。

 由论文为GFS(Google File System)Google 文件系统启发,是Google GFS的开源Java实现。


2、HDFS组件角色


2.1 NameNode
  • HDFS元数据管理者,管理NameSpace(文件系统命名空间),记录文件是如何分割成数据块以及他们分别存储在集群中的哪些数据节点上。

  • NameSpace或其本身属性的任何更改都由NameNode记录,维护整个文件系统的文件和目录。


2.2 DataNode
  • DataNode是文件系统的工作节点。根据客户端或者NameNode发送的管理指令,负责HDFS的数据块的读写和检索操作

  • 通过心跳机制定期向NameNode发送他们的存储块的列表。


2.3 Client
  • 客户端Client代表用户与NameNode或者DataNode交互来访问整个文件系统的对象。

  • 开发人员面向Client API来编程实现,对NameNode、DataNode来说透明无感。


2.4 SecondNameNode
  • 作用:一是镜像备份,二是日志与镜像的定期备份。两个过程是同时进行的,成为checkpoint。

  • 备份镜像的作用:备份fsimage。

  • 日志与镜像的定期检查作用:将NameNode中的edits日志与fsimage合并,防止NameNode意外出问题,重启时耗时过长。(主要原因是因为重启时需要重新将fsimage加载进入NN)



3、HDFS架构设计

3.1基本架构


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

3.2读文件流程


详细步骤说明:
  • 第一步:Client向NameNode发送数据请求后,寻找数据对应的数据块的位置信息。

  • 第二步:NameNode返回文件对应的数据块元数据信息,如所属机器、数据块的block_id、数据块的先后顺序等。

  • 第三步:由Client与DataNode直接通信,读取各个block数据块的信息。过程为并行读取,由客户端合并数据。


3.3写文件流程


详细步骤说明:
  • 第一步:

  • 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高可靠性措施

1、冗余备份
 数据存储在这些HDFS中的节点上,为了防止因为某个节点宕机而导致数据丢失,HDFS对数据进行冗余备份,至于具体冗余多少个副本,在dfs.replication中配置。

2、跨机架副本存放
 仅仅对数据进行冗余备份还不够,假设所有的备份都在一个节点上,那么该节点宕机后,数据一样会丢失,因此HDFS要有一个好的副本存放策略,该策略还在开发中。目前使用的是,以dfs.replication=3为例,在同一机架的两个节点上各备份一个副本,然后在另一个机架的某个节点上再放一个副本。前者防止该机架的某个节点宕机,后者防止某个机架宕机。

3、心跳检测
 DataNode节点定时向NameNode节点发送心跳包,以确保DataNode没有宕机。如果宕机,会采取相应措施,比如数据副本的备份。

4、数据完整性检测
 NameNode在创建HDFS文件时,会计算每个数据的校验和并储存起来。当客户端从DataNode获取数据时,他会将获取的数据的校验和与之前储存的校验和进行对比。

5、安全模式
 HDFS启动时,会进入安全模式,此时不允许写操作。这时,NameNode会收到所有DataNode节点的数据块报告,在确认安全之后,系统自动退出安全模式。

6、核心文件备份
 HDFS的核心文件是映像文件和事务日志,如果这些文件损坏,将会导致HDFS不可用。系统支持对这两个文件的备份,以确保NameNode宕机后的恢复。

7、空间回收

 从HDFS中删除的文件会首先被放入到/trash中,/trash文件夹中的内容是被删除文件最后的副本,该文件夹会被定时清空。该文件夹中不存在的文件就彻底不存在了。



HDFS shell应用

1、HDFS Shell命令分类


2、hdfs dfs常用命令
hdfs dfs与hadoop fs对等,只是一个先后推荐使用的区别,目前推荐使用hdfs dfs。
hdfs提供了类似shell命令的方式,可以像操作本地系统文件一样来操作hdfs文件,常用的命令如下:

2.1查看所有命令
查看hdfs dfs下的所有可用命令:


2.2查看某目录下文件列表
查看hdfs根目录下的文件列表:
    hdfs dfs -ls 


    2.3查看某文本文件的内容
    查看hdfs的某个文本文件:
      hdfs dfs -cat tmp/index.html


      2.4创建目录
      在hdfs中创建/tmp/tianliangedu目录:
        hdfs dfs – mkdir tmp/tianliangedu


        2.5删除目录
        删除/tmp/tianliangedu目录:
          hdfs dfs -rmr tmp/tianliangedu


          2.6从hdfs下载文件
          将hdfs中的/tmp/index.html文件下载到本地文件的当前路径下:
            hdfs dfs -copyToLocal tmp/index.html .


            2.7从本地上传文件到hdfs
            从本地当前目录下,上传之前的index.html文件到hdfs的/tmp/tianliangedu目录中:
              hdfs dfs -copyFromLocal index.html tmp/tianliangedu


              2.8查看压缩的文件内容
              查看压缩文本文件的格式:
                hdfs dfs -text tmp/tianliangedu/index.html.gz | more


                2.9查看文件大小
                查看hdfs中目录/tmp/tianliangedu中文件占用磁盘大小:
                  hdfs dfs -du -h tmp/tianliangedu


                  2.10创建文件
                  在/tmp/tianliangedu目录中创建空文件HelloWorld.txt:
                    hdfs dfs -touchz tmp/tianliangedu/HelloWorld.txt


                    2.11查看命令帮助信息
                    查看hdfs dfs中某个命令的用法,比如:cp:
                      hdfs dfs -usage cp


                      2.12自由练习
                      自由练习以上命令。

                      练习get、put、mv、cp、lsr、rmr等命令。依靠-usage option联系一下剩下这些指令。


                      3、hdfs dfsadmin
                      hdfs dfsadmin是集群管理员的常用命令,用来对HDFS集群的整体运行进行管理和运维。常用的管理命令如下:

                      3.1查看可用的管理命令
                      查看管理命令的帮助信息:
                        hdfs dfsadmin -help


                        3.2报告文件系统信息
                        报告文件系统的基本信息和统计信息
                          hdfs dfsadmin -report


                          3.3设置目录配额
                          设置目录配额,目录配额是一个长整型数,限定指定目录下的名字个数:
                            hdfs dfsadmin -setQuota <quota> <dirname>……<dirname>
                            比如:hdfs dfsadmin -setQuota 10 tmp/tianliangedu

                            3.4安全模式管理
                            当集群环境启动时,NameNode会进入一个安全模式。此时不会出现数据块的写操作。NameNode会收到各个DataNode拥有的数据块列表的数据块报告,由此NameNode获得所有的数据块信息。数据块达到最小副本数时,该数据块就被认为是安全的。
                              hdfs dfsadmin -safemode get   ##返回安全模式是否开启的信息,返回Safe mode is OFF/OPEN
                              hdfs dfsadmin -safemode enter ##进入安全模式
                              hdfs dfsadmin -safemode leave ##强制NameNode退出安全模式
                              hdfs dfsadmin -safemode wait ##等待,一直到安全模式结束



                              HDFS Java API应用
                              HDFS 提供了两种访问接口,除了上面介绍的Hadoop Shell接口,还另外提供了Java API 接口,对HDFS里面的文件进行操作,具体每个Block放在哪台DataNode上面,对于开发者来说是透明的,可以像操作本地系统文件一样,对HDFS进行文件上传、创建、重命名、删除等操作。
                              下面就以实际操作为例子来说明其API的具体使用。

                              操作需求
                                hdfs dfs -cat /tmp/jack/input.txt
                                从hdfs文件/tmp/jack/input.txt中读取其文本内容,并打印出来。

                                2、步骤分解


                                3、操作实现

                                3.1资源准备
                                 本地新建文件index.txt,写入“HelloWorld Hadoop”内容,上传至HDFS文件系统的/tmp/tianliangedu/input.txt文件中。

                                3.2 Maven环境搭建
                                 Maven开发环境搭建,用Eclipse IDE工具(或者是IDEA),创建一个新的Maven项目。

                                3.3 Pom配置依赖
                                修改新建项目的pom.xml的配置文件,将Hadoop的依赖加入进去:
                                • 配置依赖jar包的坐标,即描述我是谁。

                                • 指定依赖的仓库

                                • 具体需要哪些相关依赖

                                • 配置打包插件

                                具体配置参考如下:
                                  <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.tianliangedu.course</groupId>
                                     <artifactId>XjHadoopCore</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>

                                  <dependency>
                                  <groupId>org.apache.hadoop</groupId>
                                  <artifactId>hadoop-client</artifactId>
                                  <version>2.7.4</version>
                                  <scope>provided</scope>
                                  </dependency>
                                  </dependencies>
                                  <build>
                                        <finalName>XjHadoopCore</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>



                                  3.4 编码实现
                                  • 实现步骤

                                  • 定义读取的HDFS文件路径

                                  • 用HDFS Java API将HDFS文本文件转化为字符串形式

                                  1)、先将HDFS文本文件以字节数组形式读取到内存中。
                                  2)、将字节数组转换成字符串
                                  • 通过控制台将字符串打印出来

                                  • 涉及Hadoop中的类说明

                                  • Configuration(重要)

                                  1)、负责HDFS系统的配置文件的加载或者更改配置文件的工具类,将配置文件件加载到内存中。
                                  2)、通过new Configuration()初始化Configuration对象,即将HDFS的默认配置文件加载到内存中,供别的对象使用。
                                  • FileSystem

                                  1)、对HDFS系统的引用,操作HDFS的根类。所有HDFS文件操作均以此类为源头发起。
                                  2)、通过new FileSystem(new Configuration())初始化针对某集群的FileSystem对象。
                                  • Path

                                  1)、HDFS文件的抽象,与Java IO流中的File对象对等。
                                  2)、通过new Path(hdfsFilePath)得到Path对象。
                                  • FSDataInputStream

                                  1)、HDFS系统的文件字节输入流,类比于Java IO中的InputStream类,实现对HDFS文件的读取
                                  2)、FileSystem.open(filePath)可以获取HDFS的输入流
                                  • FSDataOutputStream

                                  1)、HDFS系统的文件字节输出流,类比于Java IO中的OutputStream类,实现对HDFS文件的写入。
                                  2)、FileSystem.create(filePath)可以获取HDFS的输出流
                                  • 代码实现

                                    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的路径对象Path
                                    Path 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/jack/input.txt";
                                    //将文件从hdfs读取下来,转化成字符串
                                    String result = readFromFile(hdfsFilePath);
                                    //根据题意,将字符串通过命令行输出
                                    System.out.println(result);
                                    }
                                    }
                                    • Maven打包

                                      右击项目,run as -> maven install进行打包及上传至本地仓库中,生成target目录下的XjHadoopCore-jar-with-dependencies.jar文件。

                                    • 将运行包发布上传至Hadoop环境

                                    通过rz命令,将生成的XjHadoopCore-jar-with-dependencies.jar上传到hdfs环境中。
                                    • 线上测试运行

                                      yarn jar XjHadoopCore-jar-with-dependencies.jar com.jack.utils.HdfsFileOperatorUtil

                                      • 查看验证效果




                                      文章转载自MixDream,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                      评论