HDFS作为一种新兴的并行文件系统,和现有的分布式文件系统相似,他们都是运行在普通硬件之上的分布式文件系统,然而HDFS与其他分布式文件系统也存在着一些差别。如HDFS具有高容错性,可以部署在低成本的硬件之上,同时放松了对POSIX的需求,使其可以以流的形式访问文件数据,非常适合大数据集的应用程序。分析研究HDFS与其他并行文件系统的相同点和不同点,能够深入了解HDFS系统的应用场景和设计理念。
(1)访问的透明性,用户能通过相同操作来访问本地文件和远程文件。HDFS可以做到这一点,但如果HDFS设置成本地文件系统,而不是分布式,那么HDFS的应用程序可以直接读写本地文件,只需要修改配置文件。可见,HDFS提供的访问透明性是不完全的,毕竟它构建于java之上,不能像NFS和Lustre那样去修改Unix内核,同时将本地文件和远程文件以一致地方式处理。
(2)并发控制,客户端对文件的读写不应该影响其他客户端对同一个文件的读写。要想实现这种单个文件拷贝语义,分布式文件系统需要做出复杂的交互,例如采用时间戳、采用互斥、原子操作等。而HDFS采用的机制非常简单,任何时间都只允许一个客户端进行写操作。当客户端需要写文件时,会对这个文件申请一个租约,只有这个租约被释放,别的客户端才能申请对这个文件的写操作。文件经创建并写入关闭之后不再改变,它的模型是"Write-Once-Read-Many"。
(3)资源移动策略,HDFS支持"移动计算到数据"。若一个Map任务是对某个数据块的操作,则这个操作必定是在存储这个数据块的节点上完成的,同时HDFS支持数据的多副本(默认为3个副本),存储任一副本的节点都可以执行Map任务的操作,JobTracker会把任务分配给距离客户端最近的,且存有副本的节点。
通过上面三方面的比较,可以深入的理解HDFS的优点和缺点,以及HDFS的设计应用场景。对于追求海量数据的高吞吐量、批量处理任务HDFS无疑能发挥巨大的威力,但是对文件的随机读写却并不适合。同时,HDFS也不适合对低延时访问、大量小文件的存储及处理。
分布式文件系统在物理结构上是由计算机集群中的多个节点构成的,这些节点分为两类,一类叫“主节点”(Master Node)或者也被称为“名称结点”(NameNode),另一类叫“从节点”( Slave Node )或者也被称为“数据节点”(DataNode)。
分布式文件系统的设计目标主要包括透明性、并发控制、可伸缩性、容错以及安全需求等。但是,在具体实现中,不同产品实现的级别和方式都有所不同。
(1)透明性
含义∶具备访问透明性、位置透明性和伸缩透明性
HDFS实现情况∶完全支持位置透明性和伸缩透明性
(2)并发控制
含义:客户端对于文件的读写不应该影响其他客户端对同一个文件的读写
HDFS实现情况︰机制非常简单,任何时间都只允许有一个程序在写入某个文件。
(3)文件复制(容错机制)
含义∶一个文件可以拥有在不同位置的多个副本
HDFS实现情况∶HDFS采用了多副本机制
(4)硬件和操作系统的异构性(可伸缩性)
含义︰可以在不同的操作系统和计算机上实现同样的客户端和服务器端程序。
HDFS实现情况∶采用Java语言开发,具有很好的跨平台能力
(5)容错
含义︰保证文件服务在客户端或者服务端出现问题的时候能正常使用。
HDFS实现情况︰具有多副本机制和故障自动检测、恢复机制。
(6)可伸缩性
含义∶支持节点的动态加入或退出
HDFS实现情况︰是建立在大规模廉价机器上的分布式文件系统集群,具有很好的可伸缩性。
(7)安全
含义∶保障系统的安全性
HDFS实现情况︰安全性较弱
DFS是用流处理方式处理文件,每个文件在系统里都能找到它的本地化映像,所以对于用户来说,别管文件是什么格式的,也不用在意被分到哪里,只管从DFS里取出就可以了,一般来说,文件处理过程中无法保证文件安全顺利到达,传统文件系统是使用本地校验方式保证数据完整,文件被散后,难道需要特意安排每个分片文件的校验码?
分片数量和大小是不确定的,海量的数据本来就需要海量的校验过程,分片后加入每个分片的跟踪校验完全是在数满天恒星的同时数了他们的行星。
HDFS的解决方案是分片冗余,本地校验。
直观上看,我们是给文件系统添堵,文件越来越多,实际上,DFS更加喜欢这样的架构。
数据冗余式存储,直接将多份的分片文件交给分片后的存储服务器去校验。
冗余后的分片文件还有个额外功能,只要冗余的分片文件中有一份是完整的,经过多次协同调整后,其他分片文件也将完整。
经过协调校验,无论是传输错误,I/o错误,还是个别服务器宕机,整个系统里的文件是完整的,分布后的文件系统有个无法回避的问题,因为文件不在一个磁盘导致读取访问操作的延时,这个是HDFS现在遇到的主要问题。
现阶段,HDFS的配置是按照高数据吞吐量优化的,可能会以高时间延时为代价。但万幸的是,HDFS是具有很高弹性,可以针对具体应用再优化。
HDFS优点︰
(1)兼容廉价的硬件设备:目前分布式文件系统所采用的计算机集群,都是有普通硬件构成的,这就大大降低了硬件上的开销。
(2)流数据读写:HDFS读取数据都是批量的,一次性读取全部或者说大部分的数据。
(3)单的文件模式:HDFS存储的文件都是简单模式的,一次写入多次读取,也就是说,不允许用户继续写入、修改文件。
(4)高容错性
数据自动保存多个副本。它通过增加副本的形式,提高容错性。
某一个副本丢失以后,它可以自动恢复,这是由 HDFS 内部机制实现的,我们不必关心。
(5)适合批处理
它是通过移动计算而不是移动数据。
它会把数据位置暴露给计算框架。
(6)适合大数据处理
数据规模:能够处理数据规模达到 GB、TB、甚至PB级别的数据。
文件规模:能够处理百万规模以上的文件数量,数量相当之大。
节点规模:能够处理10K节点的规模。
HDFS在实现上述优良特性的同时,也使得自身具有一些应用局限性,主要包括以下几个方面︰
实时性差要求低时间延迟的应用不适合在 HDFS 上运行,HDFS 是为高数据吞吐量应用而优化的,这可能会以高时间延迟为代价。
小文件问题由于 NameNode 将文件系统的元数据存储在内存中,因此该文件系统所能存储的文件总量受限于 NameNode 的内存总容量。
根据经验,每个文件、目录和数据块的存储信息大约占 150 字节。过多的小文件存储会大量消耗 NameNode 的存储量。
文件修改问题HDFS 中的文件只有一个写入者,而且写操作总是将数据添加在文件的末尾。HDFS 不支持具有多个写入者的操作,也不支持在文件的任意位置进行修改。
如果要处理一些用户要求时间比较短的低延迟应用请求,则HDFS不适合。HDFS是为了处理大型数据集分析任务的,主要是为达到高的数据吞吐量而设计的,这就可能要求以高延迟作为代价。
改进策略:对于那些有低延时要求的应用程序,HBase是一个更好的选择。通过上层数据管理项目来尽可能地弥补这个不足。在性能上有了很大的提升,它的口号就是goes real time。使用缓存或多master设计可以降低client的数据请求压力,以减少延时。还有就是对HDFS系统内部的修改,这就得权衡大吞吐量与低延时了,HDFS不是万能的银弹。
因为Namenode把文件系统的元数据放置在内存中,所以文件系统所能容纳的文件数目是由Namenode的内存大小来决定。一般来说,每一个文件、文件夹和Block需要占据150字节左右的空间,所以,如果你有100万个文件,每一个占据一个Block,你就至少需要300MB内存。当前来说,数百万的文件还是可行的,当扩展到数十亿时,对于当前的硬件水平来说就没法实现了。还有一个问题就是,因为Map task的数量是由splits来决定的,所以用MR处理大量的小文件时,就会产生过多的Maptask,线程管理开销将会增加作业时间。举个例子,处理10000M的文件,若每个split为1M,那就会有10000个Maptasks,会有很大的线程开销;若每个split为100M,则只有100个Maptasks,每个Maptask将会有更多的事情做,而线程的管理开销也将减小很多。
改进策略:要想让HDFS能处理好小文件,有不少方法。
利用SequenceFile、MapFile、Har等方式归档小文件,这个方法的原理就是把小文件归档起来管理,HBase就是基于此的。对于这种方法,如果想找回原来的小文件内容,那就必须得知道与归档文件的映射关系。
横向扩展,一个Hadoop集群能管理的小文件有限,那就把几个Hadoop集群拖在一个虚拟服务器后面,形成一个大的Hadoop集群。google也是这么干过的。
多Master设计,这个作用显而易见了。正在研发中的GFS II也要改为分布式多Master设计,还支持Master的Failover,而且Block大小改为1M,有意要调优处理小文件啊。
附带个Alibaba DFS的设计,也是多Master设计,它把Metadata的映射存储和管理分开了,由多个Metadata存储节点和一个查询Master节点组成。在HDFS的一个文件中只有一个写入者,而且写操作只能在文件末尾完成,
(1) 无法高效的对大量小文件进行存储
存储大量小文件的话,它会占用 NameNode大量的内存来存储文件、目录和块信息。这样是不可取的,因为NameNode的内存总是有限的。
小文件存储的寻道时间会超过读取时间,它违反了HDFS的设计目标。 改进策略。
(2) 并发写入、文件随机修改
一个文件只能有一个写,不允许多个线程同时写。
仅支持数据 append(追加),不支持文件的随机修改。
Apache Hadoop HDFS从出现到现在经过10多年的发展,已经到了非常成熟的状态,广泛应用于业界,解决海量文件的存储需求。但随着数据量的增长,以及对于数据使用方式的多样化 ,HDFS的架构局限性就逐渐被放大,NameNode在大规模场景很容易成为瓶颈。
元数据的扩展性:NameNode是一个中央元数据服务节点,也是集群管理节点,文件系统的元数据以及块位置关系全部在内存中。NameNode对内存的要求非常高,需要定制大内存的机器,内存大小也限制了集群扩展性。京东的NameNode采用内存512GB的机器,字节跳动的NameNode采用内存1TB的机器。此外,NameNode的堆分配巨大,京东的NameNode需要360GB的堆大小,对GC的要求比较高,京东定制化的JDK11+G1GC在GC时性能良好,但是一般规模的公司不具备维护JDK能力,该方案不具备普遍性。字节跳动把NameNode修改成C++版本,这样分配、释放内存都由程序控制,也达到了不错的性能,该方案仍然不具普遍性,因为开发和维护C++版本的NameNode也需要不小规模的团队。
块汇报风暴:HDFS块大小默认128M,启动几百PB数据量的集群时,NameNode需要接受所有块汇报才可以退出安全模式,因此启动时间会达数小时。当集群全量块汇报、下线节点、balance集群存储,也会对集群元数据服务的性能造成影响,这些根本原因都是DataNode需要把所有块汇报给NameNode。
全局锁:NameNode 有一把FSNamesystem全局锁,每个元数据请求时都会加这把锁。虽然是读写分开的,且有部分流程对该锁的持有范围进行了优化,但依然大问题。同时FSNamesystem内部的FSDirectory(Inode树)还存在一把单独的锁,用来保护整棵树以及BlockMap的访问和修改。
在HDFS中,名称节点( NameNode )负责管理分布式文件系统的命名空间(Namespace )。保存了两个核心的数据结构,即FsImage和EditLog.FsImage用于维护文件目录以及所有的文件的元数据,操作日志文件EditLog中记录了所有针对文件的创建、删除、重命名等操作。此外,名称节点记录了从各文件块到其所在数据节点位置的映射信息。
(1)名称节点出错
名称节点保存着最核心的连个文件FsImage和EditLog,当这两个文件损坏,那么整个文件系统都将失效。因此,HDFS设置了备份机制,通过SecondaryNameNode上的FsImage和EditLog来进行数据恢复。
(2)数据节点出错
每个数据节点会定期的想名称节点发送心跳,当网络或者数据节点出现故障时,名称节点就无法接收到心跳信息。那么将把没有心跳信息的节点标记为“宕机”,对应节点上的所有信息都会标记为“不可读”,这样就导致一些数据块副本数量小于冗余因子。名称节点会定期的检查每个副本的冗余情况,一旦发现某个文件的副本数量小于冗余因子,就会启动数据冗余复制生成新的副本。
(3)数据出错
文件被创建的时候,客户端就会对每一个文件进行信息摘录,并把这些信息写入同一路径下的隐藏文件夹下面。当客户端读取到数据后,会对每一个文件快进行MD5和sha1校验。如果校验出错,就会请求读取其他节点的同一数据块,并向名称节点报告这个文件有错误,名称节点会定期的检查并且重新复制这个块。
对于 HDFS 架构来说,一个 HDFS 基本集群包括两大部分,即 NameNode 与 DataNode节点,其作用是将管理与工作进行分离。通常来说,一个集群中会有一个 NameNode 与若干个 DataNode。 NameNode 是一个集群的主服务器,主要是用于对 HDFS 中所有的文件及内容数据进行维护,并不断读取记录集群中 DataNode 主机情况与工作状态,并通过读取与写入镜像日志文件的方式进行存储。而 DataNode 是在 HDFS 集群中担任任务具体执行,是整个集群的工作节点,文件被分成若干个相同大小的数据块,分别存储在若干个 DataNode 上,DataNode 定时定期向集群内 NameNode 发送自己的运行状态与存储内容,并根据 NameNode发送的指令进行工作。
小提示:NameNode和DataNode可以工作在一台机器上,但是此种工作方式极大的限制了HDFS性能。
NameNode 负责接受客户端发送过来的信息,然后将文件存储信息位置发送给提交请求的客户端,由客户端直接与 DataNode 进行联系,进行部分文件的运算与操作。对于文件存储来说, HDFS 使用 Block(分块)来对文件的存储进行操作。对于传统磁盘存储来说,磁盘都有默认的存储单元,通常使用的是数据定义中的最小存储单元。 Block 是HDFS 的基本存储单元,默认大小是 64M,这个大小远远大于一般系统文件的默认存储大小。这样做的一个最大好处减少文件寻址时间。
除此之外,采用 Block 对文件进行存储,大大提高了文件的灾难生存与恢复能力, HDFS还对已经存储的 Block 进行多副本备份,将每个 Block 至少复制到 3 个相互独立的硬件上。这样做的好处就是确保在发生硬件故障的时候,能够迅速的从其他硬件中读取相应的文件数据。而具体复制到多少个独立硬件上也是可以设置的。
当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit log)。
元数据节点在内存中保存了文件系统的元数据信息。在记录了修改日志后,元数据节点则修改内存中的数据结构。
每次的写操作成功之前,修改日志都会同步(sync)到文件系统。
fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在硬盘上直接修改。
同数据的机制相似,当元数据节点失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,然后逐一重新执行修改日志中的操作。
从元数据节点就是用来帮助元数据节点将内存中的元数据信息checkpoint到硬盘上。
checkpoint的过程如下:
从元数据节点通知元数据节点生成新的日志文件,以后的日志都写到新的日志文件中。
从元数据节点用http get从元数据节点获得fsimage文件及旧的日志文件。
从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。
从元数据节点奖新的fsimage文件用http post传回元数据节点 。
元数据节点可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),然后更新fstime文件,写入此次checkpoint的时间。
这样元数据节点中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变的很大了。
HDFS采用了主从( Master/Slave )结构模型,一个HDFS集群包括一个名称节点(NameNode )和若干个数据节点(DataNode )(如图3-4所示)。名称节点作为中心服务器,负责管理文件系统的命名空间及客户端对文件的访问。集群中的数据节点一般是一个节点运行一个数据节点进程,负责处理文件系统客户端的读/写请求,在名称节点的统一调度下进行数据块的创建、删除和复制等操作。每个数据节点的数据实际上是保存在本地Linux文件系统中的。
HDFS的命名空间包含目录、文件和块。命名空间管理是指命名空间支持对HDFS中的目录、文件和块做类似文件系统的创建、修改、删除等基本操作。在当前的HDFS体系结构中,在整个HDFS集群中只有一个命名空间,并且只有唯一—个名称节点,该节点负责对这个命名空间进行管理。
HDFS使用的是传统的分级文件体系,因此,用户可以像使用普通文件系统一样,创建、删除目录和文件,在目录间转移文件,重命名文件等。但是,HDFS还没有实现磁盘配额和文件访问权限等功能,也不支持文件的硬连接和软连接(快捷方式)。
(1)HDFS是一个部署在集群上的分布式文件系统,因此,很多数据需要通过网络进行传输
(2)所有的HDFS通信协议都是构建在TCP/IP协议基础之上的。
(3)客户端通过一个可配置的端口向名称节点主动发起TCP连接,并使用客户端协议与名称节点进行交互。
(4)名称节点和数据节点之间则使用数据节点协议进行交互。
(5)客户端与数据节点的交互是通过RPC ( RemoteProcedure Call )来实现的。在设计上,名称节点不会主动发起RPC,而是响应来自客户端和数据节点的RPC请求。
(1)客户端是用户操作HDFS最常用的方式,HDFS在部署时都提供了客户端。
(2)HDFS客户端是一个库,暴露了HDFS文件系统接口,这些接口隐藏了HDFS实现中的大部分复杂性。
(3)严格来说,客户端并不算是HDFS的一部分。
(4)客户端可以支持打开、读取、写入等常见的操作,并且提供了类似Shell的命令行方式来访问HDFS中的数据。
(5)此外,HDFS也提供了Java API,作为应用程序访问文件系统的客户端编程接口。
HDFS只设置唯一—个名称节点,这样做虽然大大简化了系统设计,但也带来了一些明显的局限性,具体如下∶
(1)命名空间的限制︰名称节点是保存在内存中的,因此,名称节点能够容纳的对象(文件、块)的个数会受到内存空间大小的限制。
(2)性能的瓶颈:整个分布式文件系统的吞吐量,受限于单个名称节点的吞吐量。
(3)隔离问题:由于集群中只有一个名称节点,只有一个命名空间,因此,无法对不同应用程序进行隔离。
(4)集群的可用性:一旦这个唯一的名称节点发生故障会导致整个集群变得不可用。
分布式文件系统是大数据时代解决大规模数据存储问题的有效解决方案,HDFS开源实现了GFS,可以利用由廉价硬件构成的计算机集群实现海量数据的分布式存储。
HDFS具有兼容廉价的硬件设备、流数据读写、大数据集、简单的文件模型、强大的跨平台兼容性等特点。但是,也要注意到,HDFS也有自身的局限性,比如不适合低延迟数据访问、无法高效存储大量小文件和不支持多用户写入及任意修改文件等。
块是HDFS核心的概念,一个大的文件会被拆分成很多个块。HDFS采用抽象的块概念,具有支持大规模文件存储、简化系统设计、适合数据备份等优点。
HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群包括一个名称节点和若干个数据节点。名称节点负责管理分布式文件系统的命名空间;数据节点是分布式文件系统HDFS的工作节点,负责数据的存储和读取。
HDFS采用了冗余数据存储,增强了数据可靠性,加快了数据传输速度。HDFS还采用了相应的数据存放、数据读取和数据复制策略,来提升系统整体读写响应性能。HDFS把硬件出错看作一种常态,设计了错误恢复机制。
[1]蔡斌, 陈湘萍. Hadoop 技术内幕:深入解析Hadoop Common 和HDFS 架构设计与实现原理[M]. 机械工业出版社, 2013.
[2]Hadoop 教程:
https://hadoop.apache.org/docs/r1.0.4/cn/mapred_tutorial.html
[3] Hadoop Definitive Guide 4th Edition