好程序员大数据培训分享之HDFS设计思想和相关概念:一、HDFS简介
1、简单介绍
HDFS(Hadoop Distributed FileSystem),是Hadoop项目的两大核心之一,源自于Google于2003年10月发表的GFS论文,是对GFS的开源实现。HDFS在最开始是作为Apache Nutch搜索引擎项目的基础架构而开发的。
HDFS在设计之初,就是要运行在通用硬件(commodity hardware)上,即廉价的大型服务器集群上,因此,在设计上就把硬件故障作为一种常态来考虑,可以保证在部分硬件发生故障的情况下,仍然能够保证文件系统的整体可用性和可靠性。
HDFS有一下特点:
HDFS是一个高度容错性的系统,适合部署在廉价的机器上的分布式文件系统。
HDFS能提供高吞吐量的数据访问,非常适合大规模数据集上的应用。
HDFS放宽了一部分POSIX约束,来实现流式读取文件系统数据的目的。
HDFS也是一个易于扩展的分布式文件系统
2、HDFS设计目标
a、大规模数据集
HDFS用来处理很大的数据集。HDFS上的文件,大小一般都在GB至TB。因此同时,HDFS应该能提供整体较高的数据传输带宽,能在一个集群里扩展到数百个节点。一个单一的HDFS实例应该能支撑千万计的文件。目前在实际应用中,HDFS已经能用来存储管理PB级的数据了。
b、硬件错误
我们应该知道,硬件组件发生故障是常态,而非异常情况。HDFS可能由成百上千的服务器组成,每一个服务器都是廉价通用的普通硬件,任何一个组件都有可能一直失效,因此错误检测和快速、自动恢复是HDFS的核心架构目标,同时能够通过自身持续的状态监控快速检测冗余并恢复失效的组件。
c、流式数据访问
流式数据,特点就是,像流水一样,不是一次过来而是一点一点“流”过来,而处理流式数据也是一点一点处理。
HDFS的设计要求是:能够高速率、大批量的处理数据,更多地响应"一次写入、多次读取"这样的任务。在HDFS上一个数据集,会被复制分发到不同的存储节点中。而各式各样的分析任务多数情况下,都会涉及数据集中的大部分数据。为了提高数据的吞吐量,Hadoop放宽了POSIX的约束,使用流式访问来进行高效的分析工作
d、简化一致性模型
HDFS应用需要一个“一次写入多次读取”的文件访问模型。一个文件经过创建、写入和关闭之后就不需要改变了。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能。MapReduce应用或网络爬虫应用都非常适合这个模型。目前还有计划在将来扩充这个模型,使之支持文件的附加写操作。
e、移动计算代价比移动数据代价低
一个应用请求的计算,离它操作的数据越近就越高效,这在数据达到海量级别的时候更是如此。将计算移动到数据附近,比之将数据移动到应用所在之处显然更好,HDFS提供给应用这样的接口。
f、可移植性
HDFS在设计时就考虑到平台的可移植性,这种特性方便了HDFS作为大规模数据应用平台的推广。
3、HDFS的优缺点
通过上述的介绍,我们可以发现HDFS的优点是:
a、高容错性:数据自动保存多个副本,副本丢失后,会自动恢复。
b、适合批处理:移动计算而非数据、数据位置需要暴露给计算框架。
c、适合大数据处理:GB、TB、甚至PB级数据、百万规模以上的文件数量,1000以上节点规模。
d、流式文件访问:一次性写入,多次读取;保证数据一致性。
e、可构建在廉价机器上:通过多副本提高可靠性,提供了容错和恢复机制。
而HDFS同样有自己的缺点:
1)不适合低延迟数据访问
HDFS的设计目标有一点是:处理大型数据集,高吞吐率。这势必要以高延迟为代价的。因此HDFS不适合处理一些用户要求时间比较短的低延迟应用请求。
2)不适合小文件存取
一是因此存取大量小文件需要消耗大量的寻地时间(比如拷贝大量小文件与拷贝同等大小的一个大文件) 。
二是因为namenode把元信息存储在内存中,一个节点的内存是有限的。一个block元信息的内存消耗大约是150 byte。而存储1亿个block和1亿个小文件都会消耗掉namenode 20GB内存,哪个适合?当然是1亿个block(大文件)更省内存。
3)不适合并发写入、文件随机修改
HDFS上的文件只能有一个写者,也仅仅支持append操作,不支持多用户对同一文件的写操作,以及在文件任意位置进行修改。
二、HDFS设计思想
现在想象一下这种情况:有四个文件 0.5TB的file1,1.2TB的file2,50GB的file3,100GB的file4;有7个服务器,每个服务器上有10个1TB的硬盘。
在存储方式上,我们可以将这四个文件存储在同一个服务器上(当然大于1TB的文件需要切分),我们需要使用一个文件来记录这种存储的映射关系吧。用户是可以通过这种映射关系来找到节点硬盘相应的文件的。那么缺点也就暴露了出来:
第一、负载不均衡。因为文件大小不一致,势必会导致有的节点磁盘的利用率高,有的节点磁盘利用率低。
第二、网络瓶颈问题。一个过大的文件存储在一个节点磁盘上,当有并行处理时,每个线程都需要从这个节点磁盘上读取这个文件的内容,那么就会出现网络瓶颈,不利于分布式的数据处理。
我们来看看HDFS的设计思想:以下图为例,来进行解释。
HDFS将50G的文件file3切成多个Block(存储块),每一个Block的大小都是固定的,比如128MB,它把这多个数据块以多副本的行式存储在各个节点上 ,再使用一个文件把哪个块存储在哪些节点上的映射关系存储起来。有了这样的映射关系,用户读取文件的时候就会很容易读取到。每个节点上都有这样的Block数据,它会分开网络瓶颈,利于分布式计算,解决了上面的第二个问题。因为每个块的大小是一样的,所以很容易实现负载均衡,解决了上面的第一个问题。
三、HDFS相关概念
1、块(Block)概念
在我们熟知的Windows、Linux等系统上,文件系统会将磁盘空间划分为每512字节一组,我们称之为"磁盘块",它是文件系统读写操作的最小单位。而文件系统的数据块(Block)一般是磁盘块的整数倍,即每次读写的数据量必须是磁盘块的整数倍。
在传统的文件系统中,为了提高磁盘的读写效率,一般以数据块为单位,而不是以字节为单位,比如机械硬盘包含了磁头和转动部件,在读取数据时有一个寻道的过程,通国转动盘片和移动磁头的位置,来找到数据在机械硬盘中的存储位置,然后才能进行读写。在I/O开销中,机械硬盘的寻址时间时最耗时的部分,一旦找到第一条记录,剩下的顺序读取效率是非常高的,因此以块为单位读写数据,可以把磁盘寻道时间分摊到大量数据中。
HDFS同样引入了块(Block)的概念,块是HDFS系统当中的最小存储单位,在hadoop2.0中默认大小为128MB。在HDFS上的文件会被拆分成多个块,每个块作为独立的单元进行存储。多个块存放在不同的DataNode上,整个过程中 HDFS系统会保证一个块存储在一个数据节点上 。但值得注意的是 如果某文件大小或者文件的最后一个块没有到达128M,则不会占据整个块空间 。
当然块大小可以在配置文件中hdfs-default.xml中进行修改(此值可以修改)
dfs.blocksize
134217728
默认块大小,以字节为单位。可以使用以下后缀(不区分大小写):k,m,g,t,p,e以重新指定大小(例如128k, 512m, 1g等)
dfs.namenode.fs-limits.min-block-size
1048576
以字节为单位的最小块大小,由Namenode在创建时强制执行时间。这可以防止意外创建带有小块的文件可以降级的大小(以及许多块)的性能。
<name>dfs.namenode.fs-limits.max-blocks-per-file</name>
<value>1048576</value>
<description>每个文件的最大块数,由写入时的Namenode执行。这可以防止创建会降低性能的超大文件</description></property>
HDFS中的NameNode会记录文件的各个块都存放在哪个dataNode上,这些信息一般也称为元信息(MetaInfo) 。元信息的存储位置一般由dfs.namenode.name.dir来指定。
dfs.namenode.name.dir
file://${hadoop.tmp.dir}/dfs/name
而datanode是真实存储文件块的节点,块在datanode的位置一般由dfs.datanode.data.dir来指定。
dfs.datanode.data.dir
file://${hadoop.tmp.dir}/dfs/data
HDFS上的块为什么远远大与传统文件系统,是有原因的。目的是为了最小化寻址开销时间。
HDFS寻址开销不仅包括磁盘寻道开销,还包括数据库的定位开销,当客户端需要访问一个文件时,首先从名称节点获取组成这个文件的数据块的位置列表,然后根据位置列表获取实际存储各个数据块的数据节点的位置,最后,数据节点根据数据块信息在本地Linux文件系统中找到对应的文件,并把数据返回给客户端,设计一个比较大的块,可以把寻址开销分摊到较多的数据中,相对降低了单位数据的寻址开销
举个例子: 块大小为128MB,默认传输效率100M/s ,寻址时间为10ms,那么寻址时间只占传输时间的1%左右
当然,块也不能太大,因为另一个核心技术MapReduce的map任务一次只处理一个数据块,如果任务太少,势必会降低工作的并行处理速度。
HDFS的块概念,在解决了大数据集文件的存储同时,不仅解决了文件存取的网络瓶颈问题,还
解决了大数据集文件的存储:大文件分块存储在多个数据节点上,不必受限于单个节点的存储容量。
简化系统设计:块大小固定,单个节点的块数量比较少,容易管理。元数据可以单独由其他系统负责管理。
适合数据备份:每个块可以很容易的冗余存储到多个节点上,提高了系统的容错性和可用性
2、Namenode和Datanode
HDFS集群上有两类节点,一类是管理节点(Namenode),一类是工作节点(Datanode)。而HDFS就是以管理节点-工作节点的模式运行的,在HDFS上,通常有一个Namenode和多个Datanode(一个管理者master,多个工作者slave)。
作为master的NameNode负责管理分布式文件系统的命名空间(NameSpace),即维护的是文件系统树及树内的文件和目录。这些信息以 两个核心文件(fsImage和editlog)的形式持久化在本地磁盘中。
fsImage命名空间镜像文件,用于维护文件系统树以及文件树中所有文件和目录的元数据;操作日志文件editlog中记录了所有针对文件的创建、删除、重命名等操作。namenode也记录了每个文件的各个块所在的datanode的位置信息,但并不持久化存储这些信息,而是在系统每次启动时扫描所datanode重构得到这些信息,也就是说保存在运行内存中。
Namenode在启动时,会将FsImage的内容加载到内存当中,然后执行EditLog文件中的各项操作,使得内存中的元数据保持最新。这个操作完成以后,就会创建一个新的FsImage文件和一个空的EditLog文件。名称节点启动成功并进入正常运行状态以后,HDFS中的更新操作都被写到EditLog,而不是直接写入FsImage,这是因为对于分布式文件系统而言,FsImage文件通常都很庞大,如果所有的更新操作都直接往FsImage文件中添加,那么系统就会变得非常缓慢。相对而言,EditLog通常都要远远小于FsImage,更新操作写入到EditLog是非常高效的。名称节点在启动的过程中处于“安全模式”,只能对外提供读操作,无法提供写操作。在启动结束后,系统就会退出安全模式,进入正常运行状态,对外提供写操作。
作为slave的Datanode是分布式文件系统HDFS的工作节点,负责数据块的存储和读取(会根据客户端或者Namenode的调度来进行数据的存储和检索),并且定期向Namenode发送自己所存储的块的列表。每个Datanode中的数据会被保存在本地Linux文件系统中。
3、SecondaryNamenode
在Namenode运行期间,HDFS会不断发生更新操作,这些更新操作不会直接写到fsimage文件中,而是直接被写入到editlog文件的,文件会越来越大。当Namenode重启时,会加载fsimage加载到内存中,并且逐条执行editlog中的记录,editlog文件大,就会导致整个过程变得非常缓慢,使得Namenode在启动过程中长期处于“安全模式”,无法正常对外提供写操作,影响了用户的使用。
HDFS采用了SecondaryNameNode这个守护线程,可以定期完成editlog与fsImage的合并操作,减小editlog文件大小,缩短Namenode重启时间;也可以作为Namenode的一个“检查点”,将保存Namenode内存中的元数据信息,保存在fsimage镜像文件中。