赞
踩
目录
HDFS(Hadoop Distributed File System)是Hadoop项目的核心子项目,是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的商用服务器上。
HDFS 源于 Google 在2003年10月份发表的GFS(Google File System) 论文。 它其实就是 GFS 的一个克隆版本。
随着数据量的不断增大,最终会导致数据在一个操作系统的磁盘中存储不下。那么为了存储这些大规模数据,就需要将数据分配到更多操作系统管理的磁盘中进行存储,但是这样会导致数据的管理和维护非常不方便,所以就迫切需要一种系统来管理和维护多台机器上的数据文件,实际上这种系统就是分布式文件系统,而HDFS只是分布式文件系统中的一种。
HDFS的设计理念来源于非常朴素的思想:
即当数据文件的大小超过单台计算机的存储能力时,就有必要将数据文件切分并存储到由若干台计算机组成的集群中,这些计算机通过网络进行连接。
而 HDFS 作为一个抽象层架构在集群网络之上,对外提供统一的文件管理功能,对于用户来说就感觉像在操作一台计算机一样,根本感受不到 HDFS 底层的多台计算机,而且HDFS还能够很好地容忍节点故障且不丢失任何数据。
(1)支持超大文件存储
支持超大文件存储是HDFS最基本的职责所在。
(2)流式数据访问
流式数据访问是HDFS选择的最高效的数据访问方式。流式数据访问可以理解为:读取数据文件就像打开水龙头一样,可以不停地读取。
(3)简单的一致性模型
在HDFS文件系统中,一个文件一旦经过创建、写入、关闭之后,一般就不需要再进行修改,这样就可以简单地保证数据的一致性。
(4)硬件故障的检测和快速应对
通过大量普通硬件构成的集群中,硬件出现故障是常见的问题。HDFS文件系统一般是由数十台甚至成百上千台服务器组成,这么多服务器就意味着高故障率,但是 HDFS 在设计之初已经充分 考虑到这些问题,认为硬件故障是常态而不是异常,所以如何进行故障的检测和快速自动恢复也是HDFS的重要设计目标之一。
一个完整的HDFS通常运行在由网络连接在一起的一组计算机(或者叫节点)组成的集群之上,在这些节点上运行着的不同类型的守护进程,比如NameNode、 DataNode、SecondaryNameNode,多个节点上不同类型的守护进程相互配合、相互协作,共同为用户提供高效的分布式存储服务。HDFS架构如图所示:
整个HDFS是一个主从架构。一个典型的HDFS集群中,通常会有一个NameNode、1个SecondaryNameNode和至少一个DataNode,而且HDFS客户端的数量也没有限制。
HDFS主要是为了解决大规模数据的分布式存储问题。把所需要存储的数据文件分割成数据块(Block),然后均匀的存放在运行DataNode的守护进程的节点中。由NameNode来集中管理,提供对外服务。SecondaryNameNode作为备用节点,是一个辅助NameNode的守护进程。
接下来详细介绍HDFS架构的核心组成部分:
NameNode也称为名字节点、管理节点或者元数据节点,是HDFS主从架构中的主节点,相当于HDFS的大脑,它管理文件系统的命名空间,维护着整个文件系统的目录树以及目录树中的所有子目录和文件。
这些信息以两个文件的形式持久化保存在本地磁盘上,一个是命名空间镜像FSImage(File System Image),也称为文件系统镜像,主要用来存储HDFS的元数据信息,是HDFS元数据的完整快照。NameNode每次启动时,都会默认加载最新的FSImage文件到内存中。还有一个文件是命名空间镜像的编辑日志(EditLog),该文件用于保存用户对命名空间镜像的修改信息。
SecondaryNameNode也称为从元数据节点,是HDFS主从架构中的备用节点,主要用于定期合并FSImage和EditLog,是一个辅助NameNode的守护进程。在生产环境下,SecondaryNameNode一般会单独部署到一台服务器上,因为其所在节点对这两个文件合并时需要消耗大量资源。
问:SecondaryNameNode为什么要辅助NameNode定期合并FSImage和Editlog文件?
FSImage文件实际上是HDFS元数据的一个永久检查点(CheckPoint),但并不是每一个写操作都会更新到这个文件中, 因为FSImage是一个大型文件,如果频繁地执行写操作,会导致系统运行极其缓慢。
那么该如何解决?
解决方案就是NameNode将命名空间的改动信息写入Editlog,但是随着时间的推移,Editlog文件会越来越大,一旦发生故障,那么将需要花费大量的时间进行回滚操作,所以可以像关系型数据库一样,定期合并FSImage和Editlog。但不能由NameNode来做合并操作,因为NameNode在为集群提供服务的同时可能无法提供足够的资源。为了彻底解决这一问题,SecondaryNameNode就应运而生了。
FSImage和Editlog的合并过程如图所示:
(1)SecondaryNameNode(从元数据节点)引导NameNode(元数据节点)滚动更新Editlog,并开始将新的Editlog写进edits.new。
(2)SecondaryNameNode将NameNode的FSImage(fsimage)和Editlog(edits)复制到本地的检查点目录。
(3)SecondaryNameNode将FSImage(fsimage)导入内存,并回放Editlog(edits),将其合并到FSImage(fsimage.ckpt),并将更新的FSImage(fsimage.ckpt)压缩后写入磁盘。
(4)SecondaryNameNode将新的FSImage(fsimage.ckpt)传回NameNode。
(5)NameNode在接收到新的FSImage(fsimage.ckpt)后,将fsimage.ckpt替换为fsimage,然后直接加载和启用该文件。
(6)NameNode将新的Editlog(即edits.new)更名为Editlog(即edits)。默认情况下,该过程1h发生一次,或者当EditLog达到默认值(如64MB)也会出发,具体控制参数可以通过配置文件进行修改。
DataNode也称为数据节点,它是HDFS主从架构中的从节点,它在NameNode的指导下完成数据的I/O操作。
存放在HDFS上的文件是由数据块组成的,所有的数据块都存储在DataNode节点上,实际上数据块就是一个普通文件,可以在DataNode存储块的对应目录下看到,块的名称是blk_blkID。
数据块的位置及名称如图(仅在作者个人机器上,不具有普遍性):
文件存储位置在hdfs-site.xml中自行设置。
DataNode会不断地向NameNode发送块报告(即各个DataNode节点会把本节点上存储的数据块情况以块报告的形式发送给NameNode)并执行来自NameNode的指令。
初始化时,集群中的每个DataNode会将本节点当前存储的块信息以块报告的形式告诉NameNode。在集群正常工作时,DataNode仍然会定期把最新的块信息发送给NameNode,同时接收NameNode的指令,例如,创建、移动或删除本地磁盘上的数据块等操作。
实际上,可以通过以下三点来理解DataNode是如何存储和管理数据块的:
1)DAtaNode节点以数据块的形式在本地Linux文件系统上保存HDFS文件的内容,并对外提供文件数据访问功能。
2)DataNode节点的一个基本功能是管理这些保存在Linux文件系统中的数据。
3)DataNode节点是将数据块以Linux文件的形式保存在本节点的存储系统上。
HDFS客户端是指用户和HDFS交互的手段,HDFS提供了非常多的客户端,包含命令行接口、JavaAPI、Thrift接口、Web界面等。
磁盘中有数据块(也叫磁盘块)的概念,例如,每个磁盘都有默认的磁盘块容量,磁盘块容量一般为512Byte,这是磁盘进行数据读写的最小单位。文件系统也有数据块的概念,但是文件系统中的数据块容量只能是磁盘块容量的整数倍,一般为几千字节。
然而用户在使用文件系统时,例如,对文件进行读写操作,可以完全不需要知道数据块的细节,只需要知道相关操作即可,因为这些底层细节对用户都是透明的。
HDFS也有数据块(Block)的概念,但是HDFS的数据块比一般文件系统的数据块要大得多。它是HDFS数据处理的最小单元,默认大小为128MB(在Hadoop2.0以上的版本中,默认是这些,可以通过dfs.block.size属性来配置)。这里特别需要指出的是,和其他文件系统不同,HDFS中小于一个块大小的文件并不会占据整个块的空间。
为什么HDFS中的数据块需要设置这么大?
主要是为了最小化寻址开销。因为如果将数据块设置得足够大,从磁盘传输数据的时间会明显大于定位到这个块的开始位置所需要的时间。但数据块也不能设置太大,因为这些数据块最终是要供上层计算框架来处理的,如果数据块太大,那么处理整个数据块所花费的时间就比较长,会影响整体数据处理的时间。
数据块的大小应该设置多少合适?
假设寻址时间为10ms,磁盘传输速度为100MB/s,假如寻址时间占传输时间的1%,那么块的大小可以设置为100MB,随着磁盘驱动器传输速度的不断提升,实际上数据块的大小还可以设置得更大。
(1)高容错性
数据自动保存多个副本,HDFS通过增加多个副本的形式,提高HDFS文件系统的容错性,某一个副本丢失以后可以自动恢复。
(2)适合大数据处理
能够处理GB、TB、甚至PB级别的数据规模;能够处理百万规模以上的文件数量;能够达到10000个节点以上的集群规模。
(3)流式文件访问
数据文件只能一次写入,多次读取,只能追加,不能修改;HDFS能保证数据的简单一致性。
(4)可构建在廉价的机器上
HDFS 提供了容错和恢复机制,比如某一个副本丢失了可以通过其他副本来恢复,从而保证了数据的安全性和系统的可靠性。
(1)不适合低延时数据访问
比如毫秒级别的数据响应时间,这种场景HDFS是很难做到的。HDFS更适合高吞吐率的场景,就是在某一时间内写入大量的数据。
(2)不适合大量小文件的存储
如果有大量小文件需要存储,这些小文件的元数据信息会占用NameNode大量的内存空间。这样是不可取的,因为NameNode的内存总是有限的。如果读取小文件的寻道时间超过文件数据的读取时间,它就违反了HDFS大数据块的设计目标。
(3)不适合并发写入、文件随机修改
一个文件只能有一个写操作,不允许多个线程同时进行写操作;仅支持数据的append(追加)操作,不支持文件的随机修改。
为了了解客户端及与之交互的NameNode和DataNode之间的数据流是什么样的,在读取文件时时间的发生顺序,可参考下图:
HDFS读取数据的主要步骤如下:
1)客户端通过调用FileSystem对象的open()方法来打开希望读取的文件,对于HDFS来说,这个对象是DistributedSystemd的一个实例。
2)DistributedFileSystemd通过RPC获得文件的第一批数据块的位置信息(Locations),同一个数据块按照重复数会返回多个位置信息,这些位置按照Hadoop拓扑结构排序,距离客户端近的排在前面。
3)前两步会返回一个文件系统数据输入流(FSDataInputStream)对象,该对象会被封装为分布式文件系统输入流(DFSInputStream)对象,DFSInputStream可以方便地管理DataNode和NameNode数据流。客户端调用read()方法,DFSInputStream会找出离客户端最近的DataNode并连接。
4)数据从DataNode源源不断地流向客户端。
5)如果第一个数据块的数据读完了,就会关闭指向第一个数据块的DataNode的连接,接着读取下一个数据块。这些操作对客户端来说是透明的,从客户端角度来看只是在读一个持续不断的数据流。
6)如果第一批数据块全部读完了,DFSInputStream就会去NameNode拿下一批数据块的位置信息,然后继续读。如果所有的数据块都读完了,就会关闭所有的流。
HDFS写入数据的主要步骤如下:
1)客户端通过调用DistributedFileSystem的create()方法创建新文件。
2)DistributedFileSystem通过RPC调用NameNode去创建一个没有数据块关联的新文件。在文件创建之前,NameNode会做各种校验,如文件是否存在、客户端有无权限去创建等。如果校验通过,NameNode就会创建新文件,否则就会抛出I/O异常。
3)前两步结束后,会返回文件系统数据输出流(FSDataOutputSTream)的对象,与读文件时相似,FSDataOutputStream被封装成分布式文件系统数据输出流(DFSOutputStream)。DFSOutputStream可以协调NameNode和DataNode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小的数据包(Packet),然后排成数据队列(DataQueue)。
4)数据队列中的数据包首先传输到数据管道(多个数据节点组成数据管道)中的第一个DataNode中(写数据包),第一个DataNode又把数据包发送到第二个DataNode中,依次类推。
5)DFSOutputStream还维护着一个响应队列(Ack Queue),这个队列也是由数据包组成的,用于等待DataNode收到数据后返回响应数据包,当数据管道中的所有DataNode都表示已经收到响应信息时,AckQueue才会把对应的数据包移除掉。
6)客户端写入数据完成后,会调用close()方法关闭写入流。
7)客户端通知NameNode把文件标记为已完成,然后NameNode把文件写成功的结果反馈给客户端,此时就表示客户端已完成了整个HDFS的写入数据流程。
HDFS被设计成适合运行在廉价通用硬件上的分布式文件系统,它和现有的分布式文件系统有很多共同点。但同时也有很明显的区别,那就是HDFS是一个具有高度容错性的系统。由于HDFS可以部署在廉价的商用服务器上,而廉价的服务器很容易出现故障,所以HDFS的容错性机制能够很好地保证即使节点出现故障数据也不会丢失,这就是副本技术。
副本技术也叫分布式数据复制技术,是分布式计算的一个重要组成部分。该技术允许数据在多个服务器端共享,而且一个本地服务器可以存取不同物理地点的远程服务器上的数据,也可以使所有的服务器均持有数据的副本。
通过副本技术,文件系统具有以下优点:
(1)提高系统可靠性
系统不可避免地会产生故障和错误,拥有多个副本的文件系统不会导致无法访问的情况,从而提高了系统的可用性。另外,系统可以通过其他完好的副本对发生错误的副本进行修复,从而提高了系统的容错性。
(2)负载均衡
副本可以对系统的负载量进行扩展。多个副本存放在不同的服务器上,可以分担工作量,从而将较大的工作量有效地分布在不同的节点上。
(3)提高访问效率
将副本创建在访问频度比较大的区域(即副本在访问节点的附近),相应减小了其通信开销,从而提高了整体的访问效率。
实际上就是NameNode如何选择在哪些DataNode节点上存储副本(Replication)的问题,这里需要对可靠性、写入带宽和读取带宽进行权衡。HDFS对DataNode存储副本有自己的副本策略,块副本存放位置的选择严重影响HDFS的可靠性和性能。HDFS采用机架感知(Rack Awareness)的副本存放策略来提高数据的可靠性、可用性和网络带宽的利用率。
在Hadoop发展过程中,HDFS一共有两个版本的副本策略,如图:
HDFS运行在跨越大量机架的集群之上。两个不同机架上的节点是通过交换机实现通信的,在大多数情况下,相同机架上机器之间的网络带宽优于在不同机架上的机器。
在HDFS集群启动时,每一个DataNode会自动检测它所属的机架ID,然后在向NameNode注册时告知它的机架ID。HDFS提供接口以便很容易地挂载检测机架标识的模块。
一个简单但不是最优的方式是将副本放置在不同的机架上,这就放置了机架故障时出现数据丢失,并且在读取数据时可以充分利用不同机架的带宽。这种方式均匀地将副本数据分散在集群中,简单地实现了节点故障时的负载均衡。然而这种方式增加了写的成本,因为写的时候需要跨越多个机架传输数据块。
新版本的副本存放策略的基本思想如下:
1)副本1存放在Client所在的节点上(假设Client不在集群的范围内,则第一个副本存储节点是随机选取的,当然系统会尝试不选择那些太满或者太忙的节点)。
2)副本2存放在与第一个节点不同的机架中的一个节点上(随机选择)。
3)副本3和副本2在同一个机架,随机存放在不同的节点上。
4)假设还有很多其他的副本,那么剩余的副本就随机存放在集群的各个节点中。
HDFS集群中的副本数据复制流程如下:
1)当Client向HDFS写入数据时,一开始是将数据写到本地临时文件。
2)假设数据块的副本个数为3,那么当Client本地的临时文件累积到一个数据块的大小时,Client会从NameNode获取一个DataNode列表用于存放副本。
3)Client开始向第一个DataNode中传输副本数据,第一个DataNode一小部分一小部分(4KB)地接收数据,然后将每一部分数据写入本地磁盘,同时将该部分数据传输到列表中的第二个DataNode节点。第二个DataNode也是一小部分一小部分地接收数据,然后写入本地磁盘,同时发送给第三个DataNode节点。
4)第三个DataNode接收数据并存储在本地磁盘。因此,DataNode能以流水线的方式,从上一个节点接收数据并发送给下一个节点,数据以流水线的方式从上一个DataNode复制到下一个DataNode。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。