关于HDFS的一二三

  1. HDFS 基本架构概述

 

      HDFS 最早属于 ApacheNutch 网络检索引擎的开源项目,现在属于 Hadoop 的一个子项目,其全称为 Hadoop Distributed File System,属于分布式文件系统范畴,同其他分布式文件系统类似,搭建于计算机集群之上。然而,HDFS 有着一些不同于其他分布式文件系统的特点:首先,它容错能力强,它在设计伊始,就默认存储硬件是易错的,不可靠的;其次,它可以架设在低成本的硬件上,我们可以使用最普通的 PC 机集群来搭建 HDFS;再次,它被设计用来支持大数据集的应用,具有极高的吞吐率。

      HDFS 的设计主要基于如下的考虑:

   ·HDFS 默认硬件是不可靠的,它认为硬件故障的发生是经常性的,而不是异常性的。一个 HDFS 集群可能涉及数百乃至数千台PC机,这些 PC 机构成了文件存储的实体。在一个集群中,每台机器或每个功能组件都有很大的概率发生错误,对于一个数量级极大的集群,这就意味着该集群中总是有无法正常工作的机器或组件。因此,HDFS 的核心建设目标就是迅速进行故障检测,并针对故障快速做出自动恢复响应。

   ·HDFS 没有严格遵照 POSIX 标准来实现,主要原因是因为 HDFS 是被设计用来处理大数据应用的文件系统,它更多的工作是用来进行批处理的,而不是用来同用户进行频繁的交互工作的。它更注重高吞吐量的数据访问,而不是实时的数据访问。因此,HDFS 无法完全满足 POSIX 标准的设计需求,HDFS 的设计者们修改了一些HDFS 上的实现,以使得它具有高的数据吞吐率。

    ·HDFS 被用来设计支持大数据集的应用,一个典型的文件大小可能达到 TB 级别大小。因此,HDFS 单个集群能够容纳数百个节点,能够支持数千万的文件。

    ·HDFS 的文件访问模型适用于“一次写入,多次读取”的应用程序,它默认一个文件一旦写入后基本就不再进行修改,而只是进行单纯的读取。这样的假设大大简化了数据一致性问题的解决,同时提高了数据处理的吞吐率。

    ·HDFS 认为移动计算比移动数据“更划算”,即应用处理本地数据比处理网络数据更高效,尤其是数据集规模极其庞大时,大规模的数据交换和移动可能造成严重的网络拥塞,因此,HDFS 会将数据迁移到离数据最近的节点上去执行,节点优先考虑处理本地数据。

    ·HDFS 具有强大的可移植性,它可以轻松架设在不同硬件和软件平台上。

 

     2. HDFS 架构详细说明

 

      HDFS 是一个主/从式架构的分布式文件系统。一个典型的 HDFS 集群由一个单一的NameNode 节点和一定规模数量的 DataNode 节点组成。其中 NameNode 节点用来管理文件系统命名空间,以及处理客户端的文件访问操作;DataNode节点则用来存放实际的数据块。在 HDFS 中,一个文件被分为一个或多个块(Block),这些块存储在 DataNode节点中,每个块都有一定数量的副本,副本数可配置。NameNode 节点负责解读和响应客户端发起的文件操作请求,如打开、关闭、重命名等,负责维护有关块与 DataNode节点之间的映射。DataNode 节点则实际上处理客户端发起的文件读写操作,根据NameNode 节点的指示,建立或删除相应的块。

      客户端发起读写请求时,先与 NameNode 节点进行交互。客户端向 NameNode 节点发起元数据操作请求,NameNode 节点通过元数据操作请求,并向DataNode 节点发起块操作请求。块操作请求解析成功后,DataNode 节点直接同客户端进行交互,执行读写操作。DataNode 节点间相互通信,以完成数据块的修复与备份复制。

 

      前边我们忽略了 Secondary NameNode 节点,这里我们有必要详细说明一下有关Secondary NameNode节点的作用。整个 HDFS 集群的元数据信息记录在一个叫 fsimage的文件里,该文件存储在硬盘上,属于持久化信息。对于整个文件系统元数据的操作,都会存储在一个 EditLog 文件中。NameNode 节点每次在重启时,会先加载 fsimage 文件,然后根据 EditLog 中的内容将 NameNode 节点关闭前的状态重现,将新的文件系统元数据合并到 fsimage 文件中保存,并清空 EditLog。当 NameNode 节点运行相当长一段时间时,EditLog 中的数据可能会相当庞大,若此时重启 NameNode 节点,将会使得 NameNode节点重启时间过长。Secondary NameNode 节点的工作就是在后台周期性地将 EditLog中的内容合并到 fsimage 中,然后清空 EditLog 文件。这样,NameNode 节点在重启时,免去较长时间地恢复 EditLog 中的操作,加快重启时间。

 

2.1. NameNode 节点功能及相关数据结构介绍

 

      HDFS 集群中的 NameNode 节点服务器是目录命名空间的管理者。现阶段 HDFS 集群中只有一个单一 NameNode 节点(除此外还有一个备份 NameNode 节点,称为Secondary NameNode 节点,用于故障恢复)。NameNode 节点服务器中有两个至关重要的表,这两个表存储了整个文件系统的元数据信息,分别是:

      1)文件名同块序列的映射。该表为整个文件系统目录的命名空间,静态存储,通过 FsImage 存储在 NameNode 节点所在本地硬盘之上;

      2)数据块同机器列表之间的映射。由于数据块有多个副本,因此单个数据块总是有一个机器列表同其相对应。此表相当于文件系统中的“inodes”,它不是静态存储在持久层,而是存储在内存中。每次重启 NameNode 节点时,根据 DataNode 节点反馈的blockreport 信息,该表才在 NameNode 节点内存中重新建立。

     NameNode 节点中维护了很多的数据结构,下面将介绍一下几个重要的数据结构。

   在实际代码中,NameNode 节点被动地接收服务请求,而对实际的文件操作以及元数据的维护是由FSNamesystem 类完成的。FSNamesystem接收来自客户端或DataNode 节点的请求,响应并维护整个HDFS 集群的相关元数据信息。其关键数据结构包括:FSDirectory、INode、FSImage、BlocksMap 等。

      FSDirectory 维护的是 HDFS 的整个文件目录状态。由于HDFS 的元数据信息会存储在fsimage 文件中,因此,FSDirectory负责对 fsimage 的操作。对于 HDFS 集群上所做的任何操作,NameNode 节点会记录在 EditLog 文件中,因此,FSDirectory 也同样可以对 EditLog 文件的操作。

      INode 则维护 HDFS 文件目录树结构。在 HDFS 中,目录和文件都视为是 INode,目录 INodeDirectory和文件 INodeFile 均属于 INode 的派生类。在 INodeDirectory中,存在一个成员变量,该成员变量为 List<INode>children,它记录了该目录下的子目录及文件的信息。

      FSImage 负责的是处理整个文件系统元数据的检查点和日志操作。前面有提到HDFS 的元数据信息存储在fsimage 文件中,在合并到fsimage 之前,所有的操作记录在editlog日志文件中。根据设置的参数fs.checkpoint.size 或者 fs.checkpoint.period,editlog文件超过一定大小或时间后,Secondary NameNode 节点会合并 editlog 文件到 fsimage文件中。

      BlockMap 维护的是数据块到 DataNode 节点的映射。fsimage 文件只保存了整个文件系统集群命名空间的信息,及文件名同数据块之间的映射。当集群启动时,DataNode节点会将本地 Block 的信息通过 blockreport 信息告知 NameNode 节点,NameNode 节点则通过获取得到的信息在内存中生成BlockMap数据结构中有关数据块同DataNode节点的映射。

    除了上述的几个重要的数据结构,NameNode 节点还实现了几个协议,包括客户端同 NameNode 节点交互的 ClientProtocol 协议,Secondary NameNode 节点同 NameNode节点交互的 NameNodeProtocol 协议,以及 DataNode 节点同 NameNode 节点交互的DataNodeProtocol 协议。

 

   2.2. DataNode 节点功能

 

    DataNode 节点在集群中充当的是数据实体存储的角色,他为一个 HDFS 集群存储了一个 Block 集合。一个 HDFS 集群可以有一个或者多个 DataNode 节点,每个 DataNode节点同集群中唯一的 NameNode 节点都可以进行交互,除此之外,DataNode 节点还可以同客户端以及其它 DataNode 节点进行交互。数据实体在 DataNode 节点上是以 Block的形式存在的,DataNode 节点允许客户端软件去读这些 Block,或者去写入新的 Block。DataNode 节点也可以根据 NameNode 节点的指示,对 Block 进行删除、拷贝、传输,DataNode 节点间根据 NameNode 节点的指示进行 Block 的备份,大大增强了集群的容错性。

      DataNode 节点维护这一个关键的数据结构:块与字节流的映射。该数据信息存储在本地磁盘上。DataNode 节点在集群中启动时,就会向 NameNode 节点发送该数据结构信息;在集群启动过后,DataNode 节点也会定时向 NameNode 节点发送此信息。

     NameNode 节点从不主动向 DataNode 节点发起连接或请求,而 DataNode 节点则是在集群启动的过程中,不断重复地向 NameNode 节点发送问询请求,询问 NameNode 节点自己可以做哪些工作。NameNode 节点则发送回复信息,指示 DataNode 节点完成相关工作。

    每个 DataNode 节点上都有一个开放的 socket 服务,客户端或者其他的 DataNode节点可以通过该 socket 服务连接访问该 DataNode 节点中的数据,读写相关 Block。有关socket 服务的主机号和端口号将由 DataNode 节点上报给 NameNode 节点,NameNode节点则将该信息维护好,以便告知其他 DataNode 节点或客户端。

 

    2.3. 相关通讯协议

 

ClientProtocol 协议:

    ClientProtocol 协议是客户端同 NameNode 节点之间交互的协议,但需要说明的是,客户端不能直接同 NameNode 节点进行交互,需要通过调用 DistributedFileSystem 类才能同 NameNode 节点进行交互。客户端使用此协议,可以对目录命名空间进行控制,同时,也可以对文件系统文件流进行操作,实现增加、修改、删除等文件操作。

 

NameNodeProtocol 协议:

    NameNodeProtocol 协议是 Secondary NameNode 节点同 NameNode 节点之间交互的协议,通过此协议,Secondary NameNode 节点可以获取 NameNode 节点的状态信息,获取集群文件系统元数据信息,获取相关元数据修改日志记录等,从而将 NameNode 节点的这些信息进行备份。

 

DataNodeProtocol 协议:

      DataNodeProtocol 协议是 DataNode 节点同 NameNode 节点之间交互的协议。当集群 NameNode 节点重启后,DataNode 节点向 NameNode 节点发送注册信息,并汇报本DataNode 节点上的块信息等;在文件系统运行过程中,DataNode 节点定期向 NameNode节点发送心跳协议,告知 NameNode 节点一些必要的信息,同时,询问 NameNode 节点可以做什么工作。NameNode 节点向 DataNode 节点发送回复信息,告知 DataNode 节点应该做的事情是什么。这里需要注意的是,NameNode 节点从来不会主动向 DataNode节点发起请求,而 DataNode 节点则终其一生,向 NameNode 节点不断发送询问信息。

NameNode 节点则通过回复 DataNode 节点,告知 DataNode 节点应该做的事情是什么。

 

InterDataNodeProtocol 协议:

    InterDataNodeProtocol 协议是 DataNode 节点间交互的协议,通过此协议,DataNode节点可以相互之间进行数据迁移或备份等。

 

ClientDataNodeProtocol 协议:

ClientDataNodeProtocol 协议是客户端同 DataNode 节点间交互的协议,涉及 Block的获取等信息。

 

    3. 现有 HDFS 架构不足

    前面已经说过,现有的 HDFS 采用的是主从架构,一个 HDFS 集群由一个 NameNode节点和大量 DataNode 节点组成。其所有的命名空间和元数据信息都是由 NameNode 节点来管理和维护的,客户端访问 HDFS 集群时,都是由 NameNode 节点来控制访问交互的。因此 NameNode 节点是整个集群的核心和关键。

    我们知道,NameNode 节点中保存了整个系统的命名空间,其中有两大关键的元数据结构,包括文件名与块的映射,块与 DataNode 节点的映射,这些信息在集群启动后,都会加载到 NameNode 节点的内存空间中,每个文件都要对应一个元数据信息,在内存空间中占据一定的空间大小。

    对于一定容量的 HDFS 集群,当里面的文件以大文件为主时,文件数量相对而言比较小,文件所对应的元数据信息数量也比较小,内存占用的空间也较小,同时,由于文件个体较大,文件数量较少,客户端更多的时间是在同 DataNode节点进行实际的文件读写操作,而非同 NameNode 节点进行元数据及文件操作,因此,访问性能非常好。但是,如果整个 HDFS 应用于大量小文件存储的环境时,整个 HDFS集群性能会大幅下降。首先是因为大量小文件的存在,每个小文件都需要单独的元数据信息同其对应,每个元数据信息都在内存中占用了一定的存储空间,大约需要 100 字节左右,NameNode 节点内存空间是有限的。随着小文件数量指数级的增长,小文件元数据信息势必会造成 NameNode 节点的内存空间严重不足,从而造成极大的性能瓶颈。


评论