Hdfs

Published: by Creative Commons Licence

  • Tags:

概述

引言

Hadoop分布式文件系统(HDFS)被设计为适合运行在通用硬件上的分布式文件系统。HDFS是一个高度容错的系统,适合部署在廉价机器上。HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。

大规模数据集

运行在HDFS上的应用具有很大的数据集。HDFS上的一个典型文件大小一般在G字节到T字节之间。

流式数据访问

运行在HDFS上的应用和普通应用不同,需要流式访问它们的数据集。HDFS的设计中更多考虑了数据的批处理,而不是用户交互处理。比之数据访问的低延迟问题,更关键的是在于数据访问的高吞吐量。POSIX标准对于HDFS应用的系统不是必须的,为了提高数据的吞吐量,在一些关键方面对POSIX的语义做了一些修改。

简单的一致性模型

HDFS应用需要一个一次写入多次读取的文件访问模型,一个文件经过创建写入和关闭之后就不需要改变。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能。

移动计算比移动数据更划算

一个应用请求的计算,理它的操作数据越近就越高效,在数据达到海量级别的时候尤其如此。HDFS为应用提供了将它们自己移动到数据附件的接口。

Namenode和Datanode

HDFS采用master/slave架构。一个HDFS集群由一个Namenode和若干个Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间以及客户端对文件的访问。集群中的Datanode一般是一个结点一个,负责管理它所在结点上的存储,HDFS暴露了文件系统的命名空间,用户能够以文件的形式在上面存储数据。从内部来看,一个文件事实上被分成若干个数据块,这些块存储在一组Datanode上,Namenode执行文件系统的名字空间操作,比如打开,关闭,重命名文件或目录,它也确定了数据库到具体Datanode的映射。Datanode负责处理文件系统客户端的读写请求,在Namenode的统一调度下进行数据块的创建、删除和复制。

集群中单一Namenode的结构大大简化了系统的架构,Namenode是所有HDFS元数据的管理者,用户数据永远不会流过Namenode。

文件系统的名字空间

HDFS支持传统的层次文件组织结构,用户或应用程序可以创建目录,然后将文件保存在这些目录中,文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动和重命名文件。

Namenode负责维护文件的名字空间,任何对文件系统名字空间或属性的修改都将被Namenode记录下来。应用程序可以设置HDFS保存的文件的副本数目。文件副本的数目称为文件的副本系数,这个信息也是由Namenode保存的。

数据复制

HDFS被设计为能够在一个大集群中跨机器可靠地存储超大文件。它将每个文件存储成一系列数据块,除了最后一个,所有的数据块都是同样大小的。为了容错,文件的所有数据块都会有副本,每个文件的数据块大小和副本系数都是可以配置的。应用程序可以指定某个文件的副本数目,副本系数可以在文件创建的时候指定,也可以在之后改变。HDFS的文件都是一次性写入的,并且严格要求在任何时候只能由一个写入者。

Namenode全权管理数据块的复制,它周期性地从集群中的每个Datanode接收心跳信号和块状态报告。接受到心跳信号就意味着该Datanode结点存活。块状态报告包含了一个该Datanode上所有数据块的列表。

副本存放

副本的存放是HDFS可靠性和性能的关键。优化的副本存放策略是HDFS区分于其他大部分分布式文件系统的重要特性。HDFS采用一种称为机架感知(rackaware)的策略来改进数据的可靠性、可用性和网络带宽的利用率。

大型HDFS实例一般运行在跨越多个机架的计算机组成的集群上,不同机架上的两台机器之前的通讯需要经过交换机。在大多数情况下,同一机架上的两台机器的带宽会比不同机架的两台机器间的带宽大。

通过一个机架感知的过程,Namenode可以确定每个Datanode所属的机架ID。一个简单但没有优化的策略就是将副本存放在不同的机架上。这样可以有效防止当整个机架失效时数据的丢失,并且允许读数据时充分利用多个机架的带宽,这种策略设置可以将副本均匀地分布在集群上,有利于当组件失效情况下的负载均衡。但是,因为这种策略的一个写操作需要传输数据到多个机架,这增加了写代价。

在大多数情况下,副本系数时3,HDFS的存放策略时将一个副本保存在本地机架结点上,一个副本放在同一机架的另外一个结点上,最后一个副本放在不同机架的结点上。这种策略减少了机架的数据传输,这就提高了写操作的效率。机架的错误远远比结点的错误少,所以这个策略不会影响到数据的可靠性和可用性。于此同时,因为数据块只放在两个不同的机架上,所以此策略减少了读取数据时所需的网络传输总带宽。这种策略下,副本并不是均匀分布在不同的机架上。三分之一的副本在一个结点上,三分之二的副本在一个机架上,其他副本均匀分布在剩下的机架上。

副本选择

为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。如果在读取程序的同一个机架上由一个副本,那么就读取该副本。如果一个HDFS集群跨越多个数据中心,那么客户端将首先读取本地数据中心的副本。

安全模式

Namenode启动后会进入一个称为安全模式的特殊状态。处于安全模式的Namenode是不会进行数据块的复制的。Namenode从所有的Datanode接受心跳信号和块状态报告。块状态报告包括了某个Datanode所有的数据块列表。每个数据块都有一个指定的最小副本数,当Namenode检测确定某个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全的;在一定百分比的数据块被Namenode检测确认是安全之后(加上一个额外的30秒的等待时间),Namenode将退出安全模式状态。接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他Datanode上。

文件系统元数据的持久化

Namenode上保存着HDFS的名字空间。对于任何对文件系统元数据产生修改的操作,Namenode都会使用一种称为EditLog的事务日志记录下来。整个文件系统的名字空间,包括数据块到文件的映射、文件的属性等,都存储在一个称为FsImage的文件中,这个文件也是放在Namenode所在的本地文件系统上。

Namenode在内存中保存着整个文件系统的名字空间和文件数据块映射的映像。这个关键的元数据结构设计的非常紧凑,因此一个4G内存的Namenode就足够支持大量的文件和目录了。当Namenode启动时,它从硬盘中读取Editlog和FsImage,将所有Editlog中的事务作用在内存中的FsImage上,并将这个新版本的FsImage从内存中保存到本地磁盘上,然后删除旧的Editlog。这个过程称为一个检查点(checkpoint)。

Datanode将HDFS数据以文件的形式存储在本地的文件系统中,它并不知道有关HDFS文件的信息。它把每个HDFS数据块存储在本地文件系统的一个单独的文件中。Datanode并不是同一个目录创建所有的文件,实际上,它用试探法来确定每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目录中支持大量的文件。当一个Datanode启动的时候,它会扫描本地文件系统,产生一个这些本地文件对应的所有HDFS数据块的列表,然后作为报告发送到Namenode,这个报告就是块状态报告。

通讯协议

所有的HDFS协议都是建立在TCP/IP协议之上。客户端通过一个可配置的TCP端口连接到Namenode,通过ClientProtocol协议与Namenode交互。而Datanode使用DatanodeProtocol协议与Namenode交互。一个远程过程调用模型被抽象出来封装ClientProtocol和DatanodeProtocol协议。在设计上,Namenode不会主动发起RPC,而是响应来自客户端或Datanode的RPC请求。

数据丢失

每个Datanode周期性向Namenode发送心跳信号,而Namenode根据心跳信号判断Datanode是否可用。一旦认为某个Datanode不可用将会把它标记为宕机,那么Namenode将不会再把IO请求发送给它们。任何存储在宕机Datanode上的数据将不再有效。Datanode的宕机可能会引起一些数据块的副本系数低于指定值,Namenode不断地检测这些需要的数据块,一旦发现就启动复制操作。在下列情况下需要启动复制:

  1. 某个Datanode节点失效
  2. 某个副本损坏
  3. Datanode上的硬盘错误
  4. 文件的副本系数增大

集群均衡

HDFS的架构支持数据均衡策略,如果某个Datanode节点上的可用空间低于临界值,则均衡策略系统将会自动将数据从这个Datanode迁移到其他空闲的Datanode上。

数据完整性

从某个Datanode获取的数据块可能是损坏的,损坏可能是由Datanode的存储设备错误,网络错误或者软件bug造成的。HDFS客户端软件实现了对HDFS文件内容的校验和(checksum)检查。当客户端创建一个新的HDFS文件,会计算这个文件每个数据块的校验和,并将校验和作为一个单独的隐藏文件保存在同一个HDFS名字空间下。当客户端获取文件内容后,它会校验从Datanode获取的数据跟相应的校验和文件中的校验和是否一致,如果不一致,那么客户端可以选择从其他Datanode获取该数据块的副本。

元数据磁盘错误

FsImage和Editlog是HDFS的核心数据结构,如果这些文件损坏了,整个HDFS实例都将失效。因而,Namenode可以配置成支持维护多个FsIamge和Editlog的副本。任何对FsIamge或者Editlog的修改,都将同步到它们的副本上。这种多副本的同步操作可能会降低Namenode的吞吐量,然而这个代价是可以接受的,即使HDFS的应用是数据密集的,它也不是元数据密集的。当Namenode重启的时候,它会选取最近的完整的FsIamge和Editlog来使用。

快照

HDFS被设计成支持大文件,适用HDFS的是那些需要处理大规模数据集额应用。这些应用都是只写入数据一次,但却读取多次,并且读取速度应能满足读取的需要。HDFS支持文件的一次写入多次读取语义。一个典型的数据块大小是64MB。因而,HDFS中的文件总是按照64M被切分成不同的块,每个块尽可能存储于不同的Datanode中。

Staging

客户端创建文件的请求其实并没有立即发送给Namenode,事实上,在刚开始阶段HDFS客户端会先将文件数据缓存到本地的一个临时文件。应用程序的写操作被透明地重定向到这个临时文件。当这个临时文件累积的数据量超过一个数据块的大小,客户端才会联系Namenode。Namenode将文件名插入文件系统的层次结构中,并且分配一个数据块给它。然后返回Datanode的标识符和目标数据块给客户端。接着客户端将这块从本地临时文件上传到指定的Datanode上。当文件关闭时,在临时文件中剩余的没有上传的数据也会传输到指定的Datanode上。然后客户端告诉Namenode文件已经关闭。此时Namenode才将文件创建操作提交到日志里进行存储。如果Namenode在文件关闭前宕机了,则该文件将丢失。

流水线复制

当客户端向HDFS文件写入数据的时候,一开始先写入到本地临时文件中。假设文件的副本系数是3,当本地临时文件累积到一个数据块的大小时,客户端会从Namenode获取一个Datanode列表用于存放副本。然后客户端开始向第一个Datanode传输数据,第一个Datanode一部分一部分(4KB)地接收数据,将每一部分写入到本地仓库,并同时传输该部分到列表的第二个Datanode节点。第二个Datanode也是这样,一部分一部分接收数据,写入本地仓库,并同时传输到第三个Datanode。最后,第三个Datanode接受数据并存储在本地。因此Datanode能流水线式地从前一个节点接收数据并同时转发给下一个节点,数据以流水线的方式从前一个Datanoed复制到下一个。

可访问性

HDFS给应用提供了多种访问方式。用户可以通过Java和C封装的API进行访问,还可以通过浏览器的方式访问HDFS中的文件。

DFSShell

HDFS以文件和目录的形式组织用户数据。它提供了一个命令行的接口(DFSS hell)让用户与HDFS中的数据进行交互。命令的语法和用户熟悉的其他shell贡酒类似。

文件的删除和恢复

当用户或应用程序删除某个文件时,这个文件并没有立刻从HDFS中删除。实际上,HDFS会将这个文件重命名转移到/trash目录。只要文件还在/trash目录中,该文件就能被迅速恢复。文件在/trash中保存的时间时可以配置的,当超过这个时间时,Namenode就会将该文件从名字空间中删除。删除文件会使得该文件相关的数据块被释放。注意,从用户删除文件到HDFS空闲空间的增加之间会有一定时间的延迟。

只要被删除的文件还在/trash目录中,用户就可以恢复这个文件。如果用户想恢复被删除的文件,他可以浏览/trash目录找回该文件。/trash目录仅仅保存被删除文件的最后副本。/trash目录与其他目录没有任何区别,除了一点:在该目录上HDFS会应用一个特殊策略来自动删除文件。目前的默认策略时删除/trash中保留时间超过6小时的文件。将来,这个策略可以通过一个被良好定义的接口配置。

减少副本系数

当一个文件副本系数被减少后,Namenode会选择过剩的副本删除。下次心跳检测时会将该消息传递给Datanode。Datanode遂移除相应的数据块,集群中的空闲空间加大。同样调用setReplication API结束和集群中空闲空间增加间会有一定的延迟。