Java教程

《HDFS源码剖析》--初品ing

本文主要是介绍《HDFS源码剖析》--初品ing,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

HDFS

HDFS概述

​ HDFS是Hadoop 分布式文件系统,可以运行在通用硬件上、提供流式数据操作、能够处理超大文件的分布式文件系统。HDFS具有高度容错、高吞吐量、容易扩展、高可靠性等特征。

​ HDFS是一个主/从体系结构的分布式系统,拥有1个Namenode和多个Datanodes,用户可以通过HDFS客户端同Namenode和Datanodes交互以访问文件系统。Namenode是HDFS的Master节点,负责管理文件系统的命名空间,以及数据块到具体Datanode节点的映射等信息。Datanode一般是一个节点一个,负责管理它所在节点上的存储。一个文件被分成一个或多个数据块,这些块存储在一组Datanode上Datanode以本地文件的形式保存这些数据块以及数据块的校验信息。

HDFS优点

  1. 高容错性

    • 数据自动保存多个副本,可以通过增加副本方式,提高容错性
    • 某一个副本丢失以后,可以自动恢复
  2. 适合批处理

    • 通过移动计算而不是移动数据
    • 会把数据位置暴露给计算框架
  3. 适合处理大数据

    • 能够处理PB级别的数据

    • 能够处理百万规模以上的文件数量

    • 能够处理10K节点的规模

  4. 流式文件访问

    • 一次写入,多次读取。文件一旦写入不能修改,只能追加
    • 保证数据的一致性(通过校验机制)
  5. 可构建在廉价机器上

    • 因为高容错

HDFS缺点

  1. 低延时数据访问
    • 不能毫秒级存储数据
    • 适合高吞吐率的场景,某一时间内写入大量数据。但是低延时情况下不行,比如毫秒级以内读取数据,很难做。
    • HDFS单Master,所有对文件的请求都要经过Namenode,请求多时肯定会有延时。(联邦机制应该能减轻一部分压力)。
  2. 小文件存储
    • 存储大量小文件,会占用Namenode大量内存来存储文件、目录和块信息(元信息)。
    • 小文件寻址时间会超过读取时间。
  3. 并发写入、文件随机修改
    • 一个文件只能有一个写,不允许多个线程同时写。
    • 仅支持数据append,不支持随机修改。

缺点改进

高延迟问题

  • 使用缓存或多master设计,以减轻client的数据压力。

存储小文件问题

  • 归档小文件,将小文件归档起来管理(HBase就是基于此)。如果想找回原来小文件内容,必须知道小文件与归档文件的映射关系。
  • 横向扩展,一个Hadoop集群管理小文件有限,把几个Hadoop集群拖在一个虚拟服务器里面,形成一个大的Hadoop集群。
  • 多Master设计。

HDFS基本概念

1、数据块

​ HDFS文件以数据块形式存储,数据块是HDFS文件处理(读或者写)的最小单元由于HDFS文件往往较大,同时为了最小化寻址开销,所以HDFS数据块也更大,默认是128MB。数据块以文件形式存储在Datanode的磁盘上。

​ 所有文件都会被切分成若干个数据块分布在Datanode上存储。为了实现可靠性,同一个数据块会冗余被分到不同的Datanode上,(一个数据块默认保存3份)。

​ 读操作中,HDFS客户端会首先到Namenode查找HDFS文件包含的数据块的位置信息,然后根据尾值信息从Datanode读取数据。

​ 写操作中,HDFS客户端也会首先从Namenode申请新的数据块,然后根据新申请数据块的位置信息建立数据流管道写数据。

2.Namenode

​ Namenode 管理着文件系统的命名空间(namespace),包括文件系统目录树、文件/目录信息以及文件的数据块索引,这些信息以两个文件的形式永久保存在Namenode的本地磁盘,即命名空间镜像文件和编辑日志文件。同时还保存着数据块与数据节点的对应关系,这部分数据不保存在本地磁盘,而是在Namenode启动时动态构建。HDFS客户端会通过名字节点获取上述信息,之后读写文件。

​ Namenode是HDFS的单一故障点,Hadoop2.X引入HA。同一个集群配置两个Namenode,Active-Namenode的内存元数据与Standby-Namenode完全同步

​ 因为Namenode中保存了数据块与数据节点的对应关系。如果集群文件数量过多,Namenode的内存将成为限制系统横向扩展的瓶颈。为了解决这个问题,Hadoop2.X引入联邦HDFS机制(Hadoop Federation)。其允许添加Namenode以实现命名空间的扩展,每个Namenode管理文件系统命名空间的一部分,是一个独立的名空间卷。卷之间相互独立,两两之间不通信,一个Namenode失效了也不会影响其他Namenode所维护的命名空间的可用性

3.Datanode

​ Datanode会根据HDFS客户端请求或者Namenode调度将新的数据块写入本地存储,或者读出本地存储上保存的数据块。

​ 作为从节点,Datanode会不断地向Namenode发送心跳、数据块汇报、缓存汇报,Namenode会通过心跳、数据块汇报、缓存汇报的响应向Datanode发送指令,Datanode会执行这些指令。

4.HDFS通信协议

​ 由于HDFS作为一个分布式文件系统,某些流程非常复杂,常常涉及Datanode、Namenode、Client三者之间的配合以及相互调用。为了降低耦合,HDFS将这些节点间的调用抽象成不同的接口。

​ Hadoop RPC接口:HDFS基于Hadoop RPC框架实现的接口

​ 流式接口: HDFS基于TCP或者HTTP实现的接口

HDFS主要流程

浅看,未深入源码

HDFS客户端读流程

  1. 打开HDFS文件
    • 通过DistributedFileSystem.open()方法打开HDFS文件,返回一个DFSInputSteam对象用于读取数据块。
  2. 从Namenode获取Datanode地址
    • DFSInputSteam的构造方法从Namenode获取该HDFS文件起始位置数据块的位置信息,Namenode返回的数据块的存储位置是按照与客户端的距离远近排序的,所以可以返回一个最优的Datanode节点,与这个节点建立连接读取数据块.
  3. 连接到Datanode读取数据块
    • 数据以数据包(packet)为单位从Datanode通过流式接口传送到客户端。在达到一个数据块末尾时,DFSInputStream会再次获取文件下一个数据块的位置信息,并建里这个新的数据块的最优节点之间的连接。
  4. 关闭输入流
    • 当客户端成功完成文件读取后,关闭输入流。

异常情况:

​ 读数据时,存储这个数据块的Datanode出现异常,无法读取数据。DFSInputStream会切换到另一个保存了这个数据块的数据节点读取数据

​ 数据块的应答包中不仅包含了数据,还包含校验值,HDFS客户端收到数据应答包时,会校验数据。如果出现校验错误,也就是数据节点上的这个数据块副本出现了损坏,Client会向Namenode汇报这个损坏的数据块副本,同时DFSInputStream会尝试从其他的数据节点读取这个数据块

HDFS客户端写流程

  1. 创建文件
    • 通知Namenode在文件系统目录树中的指定路径下添加一个新的空文件,并将创建新文件的操作记录到editlog中,并返回一个DFSOutputStream对象,用于执行写操作。
  2. 建立数据流管道
    • 由于只申请了空文件,并没有申请任何数据块,所以DFSOutputStream会先向Namenode申请一个新的数据块,并返回一个LocatedBlock对象,这个对象保存了存储这个数据块的所有Datanode的位置信息。获得了数据流管道中所有Datanode的信息后,DFSOutputStream既可以建立数据流管道写数据块了。
  3. 通过数据流管道写入数据
    • 建立数据流管道后,HDFS客户端就可以向数据流管道写数据了。写入DFSOutputStream的数据会先缓存在数据流中,之后被切成数据包(packet)通过管道发送到所有Datanode每个packet都有个确认包,确认包会逆序通过管道回到输出流。输出流确认了所有Datanode都写入这个packet后,就会从缓存队列删除这个packet
  4. 关闭输入流并提交文件
    • 完成了整个文件中所有数据块的写操作之后,关闭输出流。通知Namenode提交这个文件中的所有数据块

对于Datanode,当Datanode成功地接收一个新的数据块时,Datanode会向Namenode汇报,Namenode会更新内存中的数据块与数据节点的对应关系

异常情况:

​ 客户端写文件是,数据流管道中的Datanode故障,有如下故障恢复操作:

  • 输出流中缓存的没有确认的packet会重新加入发送队列输出流会为数据块申请一块新的时间戳,用新时间戳重新建立数据流管道。这保证故障Datanode上的数据块的时间戳会过期,故障恢复之后,由于数据块的时间戳与Namenode元数据中的不匹配而被删除,保证了集群中所有数据块的正确性。
  • 故障Datanode点会从Datanode列表中删除,通知Namenode分配新的Datanode到数据流管道中。接下来输出流会将新分配的Datanode添加到数据流管道中,并使用新的时间戳重新建立数据流管道。由于新添加的Datanode上并没有存储这个新的数据块,HDFS客户端会通知数据流管道中的一个Datanode复制这个数据块到新的Datanode上
  • 接下来以Datanode列表中的第一个Datanode作为"主节点",其他Datanode作为"副本节点"。
  • 数据流管道重新建立之后,输出流会更新Namenode中的元数据。故障恢复完成,客户端可以完成后续的写操作。

HDFS客户端追加写流程

追加写指打开一个已有文件并执行追加写操作,和写流程很类似,只不过在初始建立数据流管道时有些不同。

  • 打开已有的HDFS文件,获取文件最后一个数据块的位置信息,如果数据块写满则返回null。创建到这个数据块的输出流对象DFSOutputStream,获取文件租约
  • 判断最后一个数据块是否写满,
    • 如果没有写满,根据该数据块的位置信息建立到该数据块的数据流管道;
    • 如果写满了,向Namenode申请一个新的数据块之后建立数据流管道。
  • 通过数据流管道写入数据,和上面写流程类似。
  • 关闭输入流,提交文件。同上

Datanode启动、心跳以及执行Namenode指令流程

Datanode启动后与Namenode的交互主要包括三个部分:握手;注册;快汇报以及缓存汇报

Datanode启动过程

  • Datanode启动时会首先获取Namenode的版本号以及存储信息,并比较,确保Datanode和Namenode版本号一致。
  • Namenode收到注册请求后,判断当前Datanode的配置是否属于这个集群,版本号是否一致。
  • 注册成功后,Datanode将本地存储的所有数据块以及缓存的数据块上报到Namenode,Namenode会利用这些信息重新建立内存中数据块与Datanode之间的对应关系。

Datanode工作过程

  • Datanode成功启动后,需要定期向Namenode发送心跳,让Namenode知道其仍处于活动状态。Namenode会在Datanode的心跳响应中携带指令,知道Datanode进行数据块复制、删除以及恢复等操作。
  • Datanode成功添加一个新的数据块或者删除了一个已有的数据块时,向Namenode汇报,Namenode更新数据块与Datanode的对应关系。

HA切换流程

  • Active Namenode 和 Standby Namenode 是实时同步的。
  • 为了使Standby节点和Active节点状态能够同步一致,要求两个Namenode的命名空间一致并且数据块与Datanode之间的对应关系一致。
    • 命名空间一致:两个节点都要与一组独立运行的节点(JournalNodes,JNS)通信,当Acvive 执行了修改命名空间的操作时,它会定期将执行的操作记录在editlog中,并写入JNS的多数节点中。Standby 会一直监听JNS上editlog的变化,如果有改动,就会读取editlog并与当前的命名空间合并。
    • 当发生了错误切换,Standby节点会先保证已经从JNS上读取了所有的editlog并与命名空间合并,然后才切换到Active状态。
    • 数据块与Datanode对应关系的一致性:要求HDFS集群中所有的Datanode同时向这两个Namenode发送心跳以及快汇报信息。这样就完全同步了,也就可以实现热备
  • 自动Failover机制:
    • Zookeeper集群
    • ZKFailoverController:实时监控Namenode的HA状态,如果Active不可服务,那么会其会自动触发主备切换操作。

Hadoop RPC

RPC(Remote Procedure CallProtocol,远程过程调用协议),允许本地程序像调用本地方法一样调用远程机器上应用程序提供的服务。

Namenode

Namenode文件系统目录管理(第一关系管理)

Namenode数据块Datanode关系管理(第二关系管理)

Namnode文件租约管理

Namenode高可用的脑裂问题

Datanode

参考

《Hadoop 2.X HDFS源码剖析》

深入理解HDFS

HDFS——写文件中的异常处理

HadoopRPC源码解析

这篇关于《HDFS源码剖析》--初品ing的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!