HDFS--不可不知的基本知识

1.HDFS的基本介绍

HDFS 是 Hadoop Distribute File System 的简称,意为:Hadoop 分布式文件系统。是 Hadoop 核心组件之一,作为最底层的分布式存储服务而存在。
分布式文件系统解决的问题就是大数据存储。它们是横跨在多台计算机上的存储系统。分布式文件系统在大数据时代有着广泛的应用前景,它们为存储和处理超大规模数据提供所需的扩展能力。

2.HDFS的架构组成

在这里插入图片描述

3.HDFS的特性

首先,它是一个文件系统,用于存储文件,通过统一的命名空间目录树来定位文件;
其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。

master/slave 架构

HDFS 采用 master/slave 架构。一般一个 HDFS 集群是有一个 Namenode 和一定数目的Datanode 组成。Namenode 是 HDFS 集群主节点,Datanode 是 HDFS 集群从节点,两种角色各司其职,共同协调完成分布式的文件存储服务。

分块存储

HDFS 中的文件在物理上是分块存储(block)的,块的大小可以通过配置参数来规定,默认大小在 hadoop2.x 版本中是 128M。

名字空间(NameSpace)

HDFS 支持传统的层次型文件组织结构。用户或者应用程序可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。
Namenode 负责维护文件系统的名字空间,任何对文件系统名字空间或属性的修改都将被Namenode 记录下来。
HDFS 会给客户端提供一个统一的抽象目录树,客户端通过路径来访问文件,形如:hdfs://namenode:port/dir-a/dir-b/dir-c/file.data。

Namenode 元数据管理

我们把目录结构及文件分块位置信息叫做元数据。Namenode 负责维护整个hdfs文件系统的目录树结构,以及每一个文件所对应的 block 块信息(block 的id,及所在的datanode 服务器)。

Datanode 数据存储

文件的各个 block 的具体存储管理由 datanode 节点承担。每一个 block 都可以在多个datanode 上。Datanode 需要定时向 Namenode 汇报自己持有的 block信息。 存储多个副本(副本数量也可以通过参数设置 dfs.replication,默认是 3)。

副本机制

为了容错,文件的所有 block 都会有副本。每个文件的 block 大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可以在之后改变。

一次写入,多次读出

HDFS 是设计成适应一次写入,多次读出的场景,且不支持文件的修改。
正因为如此,HDFS 适合用来做大数据分析的底层存储服务,并不适合用来做.网盘等应用,因为,修改不方便,延迟大,网络开销大,成本太高。

HDFS的读取操作

在这里插入图片描述
读取数据的过程大概分为三步

一、读取前准备工作:open()

    (1)首先创建配置信息对象Configuration。
    (2)然后调用FileSystem的newInstans方法,将Configuration作为形参传入,通过反射得到一个FileSystem的对象。
    (3)然后调用FileSystem对象的open方法,因为FileSystem类是一个抽象类,它的open方法具体实现,是由它的子类DistributedFileSystem实现。
    (4)DistributedFileSystem这个类持有了一个DFSClient类的实例,最终调用的就是DFSClient实例的open方法。
    (5)这个open方法会创建一个DFSInputStream对象。
    (6)DFSInputStream对象创建时首先会给一些成员变量赋值,然后会调用openInfo()方法,该方法会通过ClientProtocolRPC接口,调用服务端
         namenode的getBlockLocations方法,获取被读取文件的前10个block块位置信息,每个位置信息会都对应的封装一个到LocatedBlock对象中,并
         将这些LocatedBlock对象放入list集合中,按照hdfs的拓扑结构进行排序。排序完成后服务端namenode会返回这个存放了block位置信息的集
         合。获取到block集合后会将该信息封装到DFSInputStream对象中。最终返回这个DFSInputStream对象。

二、开始读取:read()

    (1)客户端拿到DFSInputStream对象后,我们默认调用它的read()方法进行数据的读取。
    (2)数据的读取主要通过两个方法完成,blockSeekTo()和readBuffer()方法。
    (3)blockSeekTo()方法主要是获取在准备工作阶段已经处理好的每一个LocatedBlock对象,并从该对象中获取要连接的datanode节点信息,与该
         datanode节点建立TCP连接并发送读取请求。
    (4)当datanode节点收到读请求后,会启动一个后台线程处理这个请求,它会创建一个BlockSender对象,并对要读取的block进行校验,校验通过
         后,会返回给客户端一个响应消息,接着会通过BlockSender对象把要读取的block数据写到流中。
    (5)客户端收到datanode的响应消息后会创建一个BlockReader对象,readBuffer()方法通过BlockReader对象读取流中数据。
    (6)如果在读数据的时候,DFSInputStream和datanode的通讯发生异常,就会尝试从其他datanode读取数据,并且记录发生错误datanode,剩余的
         block读的时候就会直接跳过该datanode。DFSInputStream也会校验读取到的每一个block数据完整性,如果发现一个坏的block,就会先报告到
         namenode节点,然后尝试从其他datanode重新读取损坏的block副本数据。

三、读取完成处理:close()

    当读取完毕后会调用close()方法,把之前创建的BlockReader对象以及TCP连接全部关闭。

HDFS的写入操作

在这里插入图片描述
写入数据的过程也分为三步

一、写入前准备工作:create()

  (1)写入数据的准备工作前四步和读取差不多,差别在于调用的是DFSClient的create()方法。
 (2)这个create()方法会创建一个DFSOutputStream对象。
 (3)创建之前先会通过ClientProtocolRPC接口,调用服务端namenode的create()方法创建一个新文件,创建之前会进
      行检查工作,比如文件路径,权限等等操作。校验通过后会调用addNode()方法将该文件的路径添加到namenode的
      名称空间中,并且把这个文件的信息封装到一个HdfsFileStatus对象中,返回给客户端。
 (5)客户端接收到这个HdfsFileStatus对象后,才开始创建DFSOutputStream对象。
 (6)在创建DFSOutputStream对象过程中,首先把返回的HdfsFileStatus对象封装到DFSOutputStream对象的成员变量
      上,最重要的是会创建一个DataStreamer线程对象,这个DataStreamer线程是用来向
      datanode发送数据的,并将这个DataStream对象作为成员变量保存到DFSOutputStream对象中。
 (7)DFSOutputStream对象创建成功后,会把该这个DFSOutputStream对象放入到一个租约管理器中,最终create()返
      回这个DFSOutputStream对象给客户端。(租约管理器就是为了防止多进程操作同一个文件产生的安全问题,可以
      看做是一个写锁)

二、开始写入:write()

  (1)客户端获取到DFSOutputStream对象后,会调用write()方法准备写入数据。
  (2)写入数据前会先向namenode申请一组的block块位置信息,然后与拓扑结构最优block块所在的datanode节点
       建立TCP连接。如果TCP连接创建失败,则向namenode注销刚刚申请的block位置信息,从新申请,重新申请会把
       创建失败的datanode节点刨除。
  (3)TCP连接建立好以后就开始写入数据,对block的数据写入使用的是pipeline的方式,将数据切分成一个个的
       package,然后将这些package放入到一个data queue队里中,其实这个data queue队列就是DFSOutputStream对
       象的一个成员变量它是一个linkedlist集合,因为linkedlist底层是一个双向链表,所以对元素的增删非常快,
       因此适合做队列处理。接着就会启动在准备阶段已经创建好的DataStreamer线程对象,该线程将data queue队列
       里的每一个package发送送到datanode节点上。发送完成后,会将该package包从data
       queue队里中移除,移到另一个确认队列中,该队列和数据队列一样都是双向链表linkedlist。这个
       队列,会向datanode发送一条确认消息,用来确定package是否成功写入,当datanode成功响应确认请
       求后,会开启另一个线程responseprocess,来处理响应信息,将这个ack quene队列中的package移除掉。
  (4)当数据成功写入到最优的block以后,会由该block所在的datanode节点与需要写副本的datanode节点建立连接,
       将该block数据写入到剩余的副本block中。

三、写入完成处理:close()

   全部写完后会刷新流中的数据,然后关闭所有数据流,最后向租约管理器注销DFSOutputStream对象。

四、异常处理

   如果在写的过程中某个datanode发生错误,会采取以下几步
   关闭TCP连接;
   为了防止丢包ack quene里的packet会同步到data quene里;
   把产生错误的datanode上的还没有写完的block删除掉;
   将删除的block内容写入到其他datanode上.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值