Hadoop之分布式文件系统HDFS
2015-09-26 11:56:33 阿炯

HDFS是Hadoop Distribute File System 的简称,也就是Hadoop的一个分布式文件系统。HDFS设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。既然是分布式文件系统,首先它必须是一个文件系统,那么在Hadoop上面的文件系统会不会也像一般的文件系统一样由目录结构和一组文件构成呢?分布式是不是就是将文件分成几部分分别存储在不同的机器上呢。

------------
HDFS基本概念


数据块block:大文件会被分割成多个block进行存储,block大小默认为64MB。每一个block会在多个datanode上存储多份副本,默认是3份。

namenode:namenode负责管理文件目录、文件和block的对应关系以及block和datanode的对应关系。

datanode:datanode就负责存储了,当然大部分容错机制都是在datanode上实现的。

数据块
HDFS默认的最基本的存储单位是64M的数据块,这个数据块可以理解和一般的文件里面的分块是一样的

元数据节点和数据节点
元数据节点namenode用来管理文件系统的命名空间,它将所有的文件和文件夹的元数据保存在一个文件系统树中。

数据节点datanode就是用来存储数据文件的。

从元数据节点secondarynamenode不是我们所想象的元数据节点的备用节点,其实它主要的功能是主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。

这里先来弄清楚这个三种节点的关系吧!其实元数据节点上存储的东西就相当于一般文件系统中的目录,也是有命名空间的映射文件以及修改的日志,只是分布式文件系统就将数据分布在各个机器上进行存储罢了,下图应该就能明白了。

[hadoop@xd0 ~]$ ls dfs/datanode/current/
BP-582330060-127.0.0.1-1438670457334  VERSION


Namenode与secondarynamenode之间的进行checkpoint的过程。

------------------
HDFS的主要设计理念


1、存储超大文件
这里的“超大文件”是指几百MB、GB甚至TB级别的文件。

2、最高效的访问模式是 一次写入、多次读取
HDFS存储的数据集作为hadoop的分析对象。在数据集生成后,长时间在此数据集上进行各种分析。每次分析都将设计该数据集的大部分数据甚至全部数据,因此读取整个数据集的时间延迟比读取第一条记录的时间延迟更重要。

3、运行在普通廉价的服务器上
HDFS设计理念之一就是让它能运行在普通的硬件之上,即便硬件出现故障,也可以通过容错策略来保证数据的高可用。


--------------
HDFS基本架构



上图中有几个概念需要介绍一下

Rack 是指机柜的意思,一个block的三个副本通常会保存到两个或者两个以上的机柜中当然是机柜中的服务器,这样做的目的是做防灾容错,因为发生一个机柜掉电或者一个机柜的交换机挂了的概率还是蛮高的。

HDFS可以执行的操作有创建、删除、移动或重命名文件等,架构类似于传统的分级文件系统。需要注意的是,HDFS的架构基于一组特定的节点而构建,这是它自身的特点。HDFS包括唯一的NameNode,它在HDFS内部提供元数据服务;DataNode为HDFS提供存储块。由于NameNode是唯一的,这也是HDFS的一个弱点单点失败。

1、HDFS构架如下图所示


2、HDFS的设计
1错误检测和快速、自动的恢复是HDFS的核心架构目标。

2比之关注数据访问的低延迟问题,更关键的在于数据访问的高吞吐量。

3HDFS应用对文件要求的是write-one-read-many访问模型。

4移动计算的代价比之移动数据的代价低。

3、文件系统的namespace
Namenode维护文件系统的namespace,一切对namespace和文件属性进行修改的都会被namenode记录下来,连文件副本的数目称为replication因子,这个也是由namenode记录的。

4、数据复制
Namenode全权管理block的复制,它周期性地从集群中的每个Datanode接收心跳包和一个Blockreport。心跳包的接收表示该Datanode节点正常工作,而Blockreport包括了该Datanode上所有的block组成的列表。HDFS采用一种称为rack-aware的策略来改进数据的可靠性、有效性和网络带宽的利用。完成对副本的存放。

5、文件系统元数据的持久化
Namenode在内存中保存着整个文件系统namespace和文件Blockmap的映像。这个关键的元数据设计得很紧凑,因而一个带有4G内存的Namenode足够支撑海量的文件和目录。当Namenode启动时,它从硬盘中读取Editlog和FsImage,将所有Editlog中的事务作用apply)在内存中的FsImage,并将这个新版本的FsImage从内存中flush到硬盘上,然后再truncate这个旧的Editlog,因为这个旧的Editlog的事务都已经作用在FsImage上了。这个过程称为checkpoint。在当前实现中,checkpoint只发生在Namenode启动时,在不久的将来我们将实现支持周期性的checkpoint。

6、通信协议
所有的HDFS通讯协议都是构建在TCP/IP协议上。客户端通过一个可配置的端口连接到Namenode,通过ClientProtocol与Namenode交互。而Datanode是使用DatanodeProtocol与Namenode交互。从ClientProtocol和Datanodeprotocol抽象出一个远程调用(RPC,在设计上,Namenode不会主动发起RPC,而是是响应来自客户端和Datanode的RPC请求。


---------------------
HDFS中的数据流读写过程


读文件

客户端(client)用FileSystem的open()函数打开文件,DistributedFileSystem用RPC调用元数据节点,得到文件的数据块信息。对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。DistributedFileSystem返回FSDataInputStream给客户端,用来读取数据。客户端调用stream的read()函数开始读取数据。DFSInputStream连接保存此文件第一个数据块的最近的数据节点。Data从数据节点读到客户端(client),当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。

整个过程如图所示:




写文件

客户端调用create()来创建文件,DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件。元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。DistributedFileSystem返回DFSOutputStream,客户端用于写数据。客户端开始写入数据,DFSOutputStream将数据分成块,写入dataqueue。Dataqueue由DataStreamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。DataStreamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。DFSOutputStream为发出去的数据块保存了ackqueue,等待pipeline中的数据节点告知数据已经写入成功。如果数据节点在写入的过程中失败:关闭pipeline,将ackqueue中的数据块放入dataqueue的开始。

整个过程如图所示:



----------------
HDFS不适用做什么

1、将HDFS用于对数据访问要求低延迟的场景
由于HDFS是为高数据吞吐量应用而设计的,必然以高延迟为代价。

2、存储大量小文件
HDFS中元数据文件的基本信息存储在namenode的内存中,而namenode为单点,小文件数量大到一定程度,namenode内存就吃不消了。

-------------
HDFS Balancer

Hadoop的HDFS集群非常容易出现机器与机器之间磁盘利用率不平衡的情况,比如集群中添加新的数据节点。当HDFS出现不平衡状况的时候,将引发很多问题,比如MR程序无法很好地利用本地计算的优势,机器之间无法达到更好的网络带宽使用率,机器磁盘无法利用等等。可见,保证HDFS中的数据平 衡是非常重要的。

在Hadoop中,包含一个Balancer程序,通过运行这个程序,可以使得HDFS集群达到一个平衡的状态,使用这个程序的命令如下:
bash $HADOOP_HOME/bin/start-balancer.sh –t 10%

这个命令中-t参数后面跟的是HDFS达到平衡状态的磁盘使用率偏差值,如果机器与机器之间磁盘使用率偏差小于10%,那么我们就认为HDFS集群已经达到了平衡的状态。

Hadoop的开发人员在开发Balancer程序的时候,遵循了以下几点原则:

1、在执行数据重分布的过程中,必须保证数据不能出现丢失,不能改变数据的备份数,不能改变每一个rack中所具备的block数量。

2、系统管理员可以通过一条命令启动数据重分布程序或者停止数据重分布程序。

3、Block在移动的过程中,不能暂用过多的资源,如网络带宽。

4、数据重分布程序在执行的过程中,不能影响name node的正常工作。

基于这些基本点,目前Hadoop数据重分布程序实现的逻辑流程如下图所示:


Rebalance程序作为一个独立的进程与namenode进行分开执行。

1、Rebalance Server从Name Node中获取所有的Data Node情况:每一个Data Node磁盘使用情况。

2、Rebalance Server计算哪些机器需要将数据移动,哪些机器可以接受移动的数据。并且从Name Node中获取需要移动的数据分布情况。

3、Rebalance Server计算出来可以将哪一台机器的block移动到另一台机器中去。

4,5,6、需要移动block的机器将数据移动的目的机器上去,同时删除自己机器上的block数据。

7、Rebalance Server获取到本次数据移动的执行结果,并继续执行这个过程,一直没有数据可以移动或者HDFS集群以及达到了平衡的标准为止。

Hadoop现有的这种Balancer程序工作的方式在绝大多数情况中都是非常适合的。

现在我们设想这样一种情况:

1、数据是3份备份。

2、HDFS由2个rack组成。

3、2个rack中的机器磁盘配置不同,第一个rack中每一台机器的磁盘空间为1TB,第二个rack中每一台机器的磁盘空间为10TB。

4、现在大多数数据的2份备份都存储在第一个rack中。

在这样的一种情况下,HDFS级群中的数据肯定是不平衡的。现在我们运行Balancer程序,但是会发现运行结束以后,整个HDFS集群中的数据依旧不平衡:rack1中的磁盘剩余空间远远小于rack2。

这是因为Balance程序的开发原则1导致的。

简单的说,就是在执行Balancer程序的时候,不会将数据中一个rack移动到另一个rack中,所以就导致了Balancer程序永远无法平衡HDFS集群的情况。

针对于这种情况,可以采取2种方案:
继续使用现有的Balancer程序,但是修改rack中的机器分布,将磁盘空间小的机器分叉到不同的rack中去。修改Balancer程序,允许改变每一个rack中所具备的block数量,将磁盘空间告急的rack中存放的block数量减少,或者将其移动到其他磁盘空间更多的rack中去。

本文总结自:http://os.51cto.com/