1、Hadoop分布式文件系统架构和源码分析报告Hadoop分布式文件系统(HDFS)的架构及代码分析报告课程名称:高级网络计算授课教师:陈波考核方式:考查姓名:胡必玲学号:200921060360摘要: 分布式开源框架Hadoop是一个用于运行应用程序在大型集群的廉价硬件设备上的框架,它为应用程序透明的提供了一组稳定/可靠的接口和数据运动。Hadoop框架中最核心的设计就是:MapReduce和HDFS。简单的一句话解释MapReduce就是“任务的分解与结果的汇总”。HDFS是Hadoop分布式文件系统(Hadoop Distributed File System)的缩写,为分布式计算存储提供
2、了底层支持。本文是在认真研读HDFS源代码以及其结构设计的基础上,所写出的一篇分析报告和学习小结。主要包括两个方面的内容:一是Hadoop中HDFS架构和设计的理解;二是HDFS源代码的理解分析。Abstract:The distributed open-source software Hadoop is a frame which could run applications in large cluster commodity computers. It provides applications with a set of stable/reliable interfaces and d
3、ata movement transparently. The core design in the frame is MapReduce and HDFS. MapReduce, a simple word to explain, is split the tasks and combine the results. HDFS is the abbreviation for Hadoop Distributed File System,Which supports distributed computing storage in the bottom. This article is wri
4、tten on the basis of reading source code of HDFS and its architecture design. It mainly includes the understanding of HDFS architecture design and its source code. 1. HDFS的架构和设计分析 4 1.1 引言 4 1.2 HDFS 的体系结构 51.3 文件系统的命名空间 61.4 数据复制 71.5 文件系统元数据持久化的实现 81.6 HDFS的通讯协议 91.7 健壮性的实现 91.8 数据是如何组织的? 101.9 应用
5、程序如何实现访问 111.10 存储空间的回收 112HDFS源码的理解和分析 122.1 集群系统工作状态 122.2 Data Node 源码分析 132.3 Name Node 源码分析(略) 2.4 DFSClient 源码分析(略) 3结论 324. 后记 33 正文1、 HDFS的架构和设计分析1、1 引言 Hadoop分布式文件系统(HDFS)是被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统。它和现有的分布式文件系统有很多共同点。但同时,它和其他的分布式文件系统的区别也是很明显的。HDFS是一个高度容错性的系统,适合部署在廉价的机器上;它能提
6、供高吞吐量的数据访问,非常适合大规模数据集上的应用;HDFS放宽了一部分POSIX约束,来实现流式读取文件系统数据的目的。在HDFS中,由于其基本上是由成百上千个服务器所组成,每个服务器上存储着文件系统的部分数据。所以由于构成系统的组件数目是巨大的,而且任一组件都有可能失效,这意味着总是有一部分HDFS的组件是不工作的。因此错误检测和快速、自动的恢复是HDFS最核心的架构目标;而关于数据的访问方式方面,由于运行在HDFS上的应用和普通的应用不同,需要流式访问它们的数据集。HDFS的设计中更多的考虑到了数据批处理,而不是用户交互处理;运行在HDFS上的应用具有很大的数据集。HDFS上的一个典型文
7、件大小一般都在G字节至T字节。因此,HDFS被调节以支持大文件存储。它应该能提供整体上高的数据传输带宽,能在一个集群里扩展到数百个节点。一个单一的HDFS实例应该能支撑数以千万计的文件;HDFS应用需要一个“一次写入多次读取”的文件访问模型。一个文件经过创建、写入和关闭之后就不需要改变。这一假设简化了数据一致性问题,并且使高吞吐量的数据访问成为可能。一个应用请求的计算,离它操作的数据越近就越高效,在数据达到海量级别的时候更是如此。因为这样就能降低网络阻塞的影响,提高系统数据的吞吐量。将计算移动到数据附近,比之将数据移动到应用所在显然更好。HDFS为应用提供了将它们自己移动到数据附近的接口; H
8、DFS在设计的时候就考虑到平台的可移植性。这种特性方便了HDFS作为大规模数据应用平台的推广。 1.2 HDFS 的体系结构 HDFS采用master/slave架构。一个HDFS集群是由一个Namenode和一定数目的Data nodes组成。Name node是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点一个,负责管理它所在节点上的存储。HDFS暴露了文件系统的名字空间,用户能够以文件的形式在上面存储数据。从内部看,一个文件其实被分成一个或多个数据块,这些块存储在一组Datanode上。Namenode执行文
9、件系统的名字空间操作,比如打开、关闭、重命名文件或目录。它也负责确定数据块到具体Datanode节点的映射。Datanode负责处理文件系统客户端的读写请求。在Namenode的统一调度下进行数据块的创建、删除和复制。Namenode和Datanode被设计成可以在普通的商用机器上运行。这些机器一般运行着GNU/Linux操作系统(OS)。HDFS采用Java语言开发,因此任何支持Java的机器都可以部署Namenode或Datanode。由于采用了可移植性极强的Java语言,使得HDFS可以部署到多种类型的机器上。一个典型的部署场景是一台机器上只运行一个Namenode实例,而集群中的其它机
10、器分别运行一个Datanode实例。这种架构并不排斥在一台机器上运行多个Datanode,只不过这样的情况比较少见。 下面的图1.2简单勾画了HDFS的体系结构。 上图中展现了整个HDFS三个重要角色:NameNode、DataNode和Client。以下通过三个操作来说明它们之间的交互关系:1、文件写入: Client向NameNode发起文件写入的请求。 NameNode根据文件大小和文件块配置情况,返回给Client它所管理部分DataNode的信息。 Client将文件划分为多个Block,根据DataNode的地址信息,按顺序写入到每一个DataNode块中。 2、 文件读取: Cl
11、ient向NameNode发起文件读取的请求。 NameNode返回文件存储的DataNode的信息。 Client读取文件信息。 3、 文件Block复制: NameNode发现部分文件的Block不符合最小复制数或者部分DataNode失效。 通知DataNode相互复制Block。 DataNode开始直接相互复制。 1.3 文件系统的命名空间HDFS支持传统的层次型文件组织结构。用户或者应用程序可以创建目录,然后将文件保存在这些目录里。文件系统名字空间的层次结构和大多数现有的文件系统类似:用户可以创建、删除、移动或重命名文件。当前,HDFS不支持用户磁盘配额和访问权限控制,也不支持硬链
12、接和软链接。但是HDFS架构并不妨碍实现这些特性。 Namenode负责维护文件系统的名字空间,任何对文件系统名字空间或属性的修改都将被Namenode记录下来。应用程序可以设置HDFS保存的文件的副本数目。文件副本的数目称为文件的副本系数,这个信息也是由Namenode保存的。1.4 数据复制HDFS被设计成能够在一个大集群中跨机器可靠地存储超大文件。它将每个文件存储成一系列的数据块,除了最后一个数据块外,其余所有的数据块都是同样大小的。为了容错,文件的所有数据块都会有副本。每个文件的数据块大小和副本系数都是可配置的。应用程序可以指定某个文件的副本数目。副本系数可以在文件创建的时候指定,也可
13、以在之后改变。HDFS中的文件都是一次性写入的,并且严格要求在任何时候只能有一个写入者。 Namenode全权管理数据块的复制,它周期性地从集群中的每个Datanode接收心跳信号和块状态报告(Blockreport)。接收到心跳信号意味着该Datanode节点工作正常。块状态报告包含了一个该Datanode上所有数据块的列表。 而在整个系统设计之初,最首先的一步就是副本的存放。副本的存放是HDFS可靠性和性能的关键。优化的副本存放策略是HDFS区分于其他大部分分布式文件系统的重要特性。这种特性需要做大量的调优,并需要经验的积累。HDFS采用一种称为机架感知(rack-aware)的策略来改进
14、数据的可靠性、可用性和网络带宽的利用率。目前实现的副本存放策略只是在这个方向上的第一步。实现这个策略的短期目标是验证它在生产环境下的有效性,观察它的行为,为实现更先进的策略打下测试和研究的基础。 大型HDFS实例一般运行在跨越多个机架的计算机组成的集群上,不同机架上的两台机器之间的通讯需要经过交换机。在大多数情况下,同一个机架内的两台机器间的带宽会比不同机架的两台机器间的带宽大。通过一个机架感知的过程,Namenode可以确定每个Datanode所属的机架id。一个简单但没有优化的策略就是将副本存放在不同的机架上。这样可以有效防止当整个机架失效时数据的丢失,并且允许读数据的时候充分利用多个机架
15、的带宽。这种策略设置可以将副本均匀分布在集群中,有利于当组件失效情况下的负载均衡。但是,因为这种策略的一个写操作需要传输数据块到多个机架,这增加了写的代价。在大多数情况下,副本系数是3,HDFS的存放策略是将一个副本存放在本地机架的节点上,一个副本放在同一机架的另一个节点上,最后一个副本放在不同机架的节点上。这种策略减少了机架间的数据传输,这就提高了写操作的效率。机架的错误远远比节点的错误少,所以这个策略不会影响到数据的可靠性和可用性。于此同时,因为数据块只放在两个(不是三个)不同的机架上,所以此策略减少了读取数据时需要的网络传输总带宽。在这种策略下,副本并不是均匀分布在不同的机架上。三分之一
16、的副本在一个节点上,三分之二的副本在一个机架上,其他副本均匀分布在剩下的机架中,这一策略在不损害数据可靠性和读取性能的情况下改进了写的性能。 而在程序进行读取的过程中,为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。如果在读取程序的同一个机架上有一个副本,那么就读取该副本。如果一个HDFS集群跨越多个数据中心,那么客户端也将首先读本地数据中心的副本。 还有一点值得注意的是Namenode启动后会进入一个称为安全模式的特殊状态。处于安全模式的Namenode是不会进行数据块的复制的。Namenode从所有的 Datanode接收心跳信号和块状态报告。块状态报告包括了
17、某个Datanode所有的数据块列表。每个数据块都有一个指定的最小副本数。当Namenode检测确认某个数据块的副本数目达到这个最小值,那么该数据块就会被认为是副本安全(safely replicated)的;在一定百分比(这个参数可配置)的数据块被Namenode检测确认是安全之后(加上一个额外的30秒等待时间),Namenode将退出安全模式状态。接下来它会确定还有哪些数据块的副本没有达到指定数目,并将这些数据块复制到其他Datanode上。 整个HDFS的数据复制以及程序访问过程就如上所述。1.5 文件系统元数据持久化的实现Namenode上保存着HDFS的名字空间。对于任何对文件系统元
18、数据产生修改的操作,Namenode都会使用一种称为EditLog的事务日志记录下来。例如,在HDFS中创建一个文件,Namenode就会在Editlog中插入一条记录来表示;同样地,修改文件的副本系数也将往Editlog插入一条记录。Namenode在本地操作系统的文件系统中存储这个Editlog。整个文件系统的名字空间,包括数据块到文件的映射、文件的属性等,都存储在一个称为FsImage的文件中,这个文件也是放在Namenode所在的本地文件系统上。 Namenode在内存中保存着整个文件系统的名字空间和文件数据块映射(Blockmap)的映像。这个关键的元数据结构设计得很紧凑,因而一个有
19、4G内存的Namenode足够支撑大量的文件和目录。当Namenode启动时,它从硬盘中读取Editlog和FsImage,将所有Editlog中的事务作用在内存中的FsImage上,并将这个新版本的FsImage从内存中保存到本地磁盘上,然后删除旧的Editlog,因为这个旧的Editlog的事务都已经作用在FsImage上了。这个过程称为一个检查点(checkpoint)。在当前实现中,检查点只发生在Namenode启动时,在不久的将来将实现支持周期性的检查点。 Datanode将HDFS数据以文件的形式存储在本地的文件系统中,它并不知道有关HDFS文件的信息。它把每个HDFS数据块存储在
20、本地文件系统的一个单独的文件中。Datanode并不在同一个目录创建所有的文件,实际上,它用试探的方法来确定每个目录的最佳文件数目,并且在适当的时候创建子目录。在同一个目录中创建所有的本地文件并不是最优的选择,这是因为本地文件系统可能无法高效地在单个目录中支持大量的文件。当一个Datanode启动时,它会扫描本地文件系统,产生一个这些本地文件对应的所有HDFS数据块的列表,然后作为报告发送到Namenode,这个报告就是块状态报告。 1.6 HDFS的通讯协议 所有的HDFS通讯协议都是建立在TCP/IP协议之上。客户端通过一个可配置的TCP端口连接到Namenode,通过ClientProt
21、ocol协议与Namenode交互。而Datanode使用DatanodeProtocol协议与Namenode交互。一个远程过程调用(RPC)模型被抽象出来封装ClientProtocol和Datanodeprotocol协议。在设计上,Namenode不会主动发起RPC,而是响应来自客户端或 Datanode 的RPC请求。1.7 健壮性的实现HDFS的主要目标就是即使在出错的情况下也要保证数据存储的可靠性。常见的三种出错情况是:Namenode出错, Datanode出错和网络割裂(network partition)。网络割裂可能导致一部分Datanode跟Namenode失去联系。但
22、是由于每个Datanode节点都会周期性地向Namenode发送心跳信号。Namenode可以通过心跳信号的缺失来检测这一情况,并将这些近期不再发送心跳信号的Datanode标记为宕机,不会再将新的IO请求发给它们。任何存储在宕机Datanode上的数据将不再有效。Datanode的宕机可能会引起一些数据块的副本系数低于指定值,Namenode不断地检测这些需要复制的数据块,一旦发现就启动复制操作。HDFS的架构能够支持数据均衡。如果某个Datanode节点上的空闲空间低于特定的临界点,按照均衡策略系统就会自动地将数据从这个Datanode移动到其他空闲的Datanode。当对某个文件的请求突
23、然增加,那么也可能启动一个计划创建该文件新的副本,并且同时重新平衡集群中的其他数据。除此以外,针对数据完整性方面,由于从某个Datanode获取的数据块有可能是损坏的,损坏可能是由Datanode的存储设备错误、网络错误或者软件bug造成的。HDFS客户端软件实现了对HDFS文件内容的校验和(checksum)检查。当客户端创建一个新的HDFS文件,会计算这个文件每个数据块的校验和,并将校验和作为一个单独的隐藏文件保存在同一个HDFS名字空间下。当客户端获取文件内容后,它会检验从Datanode获取的数据跟相应的校验和文件中的校验和是否匹配,如果不匹配,客户端可以选择从其他Datanode获取
24、该数据块的副本。而对于存储在Namenode 上的元数据发生错误,如FsImage和Editlog,它们是HDFS的核心数据结构。如果这些文件损坏了,整个HDFS实例都将失效。因而,Namenode可以配置成支持维护多个FsImage和Editlog的副本。任何对FsImage或者Editlog的修改,都将同步到它们的副本上。这种多副本的同步操作可能会降低Namenode每秒处理的名字空间事务数量。然而这个代价是可以接受的,因为即使HDFS的应用是数据密集的,它们也非元数据密集的。当Namenode重启的时候,它会选取最近的完整的FsImage和Editlog来使用。 Namenode是HDF
25、S集群中的单点故障(single point of failure)所在。如果Namenode机器故障,是需要手工干预的。目前,自动重启或在另一台机器上做Namenode故障转移的功能还没实现。 HDFS同样计划在未来的版本中支持快照来支持数据的复制备份,利用快照,可以让HDFS在数据损坏时恢复到过去一个已知正确的时间点。1.8数据是如何组织的? HDFS被设计成支持大文件,适用HDFS的是那些需要处理大规模的数据集的应用。这些应用都是只写入数据一次,但却读取一次或多次,并且读取速度应能满足流式读取的需要。HDFS支持文件的“一次写入多次读取”语义。一个典型的数据块大小是64MB。因而,HDF
26、S中的文件总是按照64M被切分成不同的块,每个块尽可能地存储于不同的Datanode中。 在客户端创建文件的过程中,客户端创建文件的请求其实并没有立即发送给Namenode,事实上,在刚开始阶段HDFS客户端会先将文件数据缓存到本地的一个临时文件。应用程序的写操作被透明地重定向到这个临时文件。当这个临时文件累积的数据量超过一个数据块的大小,客户端才会联系Namenode。Namenode将文件名插入文件系统的层次结构中,并且分配一个数据块给它。然后返回Datanode的标识符和目标数据块给客户端。接着客户端将这块数据从本地临时文件上传到指定的Datanode上。当文件关闭时,在临时文件中剩余的
27、没有上传的数据也会传输到指定的Datanode上。然后客户端告诉Namenode文件已经关闭。此时Namenode才将文件创建操作提交到日志里进行存储。如果Namenode在文件关闭前宕机了,则该文件将丢失。 当客户端向HDFS文件写入数据的时候,由于一个文件通常有几个副本。HDFS实行流水线复制来进行数据的写入。一开始是将数据写到本地临时文件中。假设该文件的副本系数设置为3,当本地临时文件累积到一个数据块的大小时,客户端会从Namenode获取一个Datanode列表用于存放副本。然后客户端开始向第一个Datanode传输数据,第一个Datanode一小部分一小部分(4 KB)地接收数据,将
28、每一部分写入本地仓库,并同时传输该部分到列表中第二个Datanode节点。第二个Datanode也是这样,一小部分一小部分地接收数据,写入本地仓库,并同时传给第三个Datanode。最后,第三个Datanode接收数据并存储在本地。因此,Datanode能流水线式地从前一个节点接收数据,并在同时转发给下一个节点,数据以流水线的方式从前一个Datanode复制到下一个。 1.9 应用程序如何实现访问 HDFS是以文件和目录的形式来组织用户数据的,它给应用提供了多种访问方式。程序可以通过JAVA API接口或者是C语言封装的API接口来访问数据,还可以通过浏览器来访问其中的文件。1.10 存储空间
29、的回收 当我们要删除某个文件,或者减少一个文件的副本系数进而要删除它的一个副本的时候,就存在着存储空间的回收问题。在HDFS中,当用户或应用程序删除某个文件时,这个文件并没有立刻从HDFS中删除。实际上,HDFS会将这个文件重命名转移到/trash目录。只要文件还在/trash目录中,该文件就可以被迅速地恢复。文件在/trash中保存的时间是可配置的,当超过这个时间时,Name node就会将该文件从名字空间中删除。而该文件相关的数据块将被释放。所以,从用户删除文件到HDFS空闲空间的增加之间会有一定时间的延迟。只要被删除的文件还在/trash目录中,用户就可以恢复这个文件。如果用户想恢复被删
30、除的文件,他/她可以浏览/trash目录找回该文件。/trash目录仅仅保存被删除文件的最后副本。/trash目录与其他的目录没有什么区别,除了一点:在该目录上HDFS会应用一个特殊策略来自动删除文件。目前的默认策略是删除/trash中保留时间超过6小时的文件。当一个文件的副本系数被减小后,Name node会选择过剩的副本删除。下次心跳检测时会将该信息传递给Data node。Data node遂即移除相应的数据块,集群中的空闲空间加大。同样,在调用set Replication API结束和集群中空闲空间增加间会有一定的延迟。以上是从HDFS的体系结构,数据复制,健壮性和数据组织等九个方面
31、对于Hadoop的文件系统进行的理解和分析。下面的第二大部分着重理解了HDFS的源码。2、HDFS源码的理解和分析一个典型的HDFS系统包括一个NameNode和多个DataNode。NameNode维护名字空间;而DataNode存储数据块。DataNode负责存储数据,一个数据块在多个DataNode中有备份;而一个DataNode对于一个块最多只包含一个备份。所以我们可以简单地认为DataNode上存了数据块ID和数据块内容,以及他们的映射关系。一个HDFS集群可能包含上千DataNode节点,这些DataNode定时和NameNode通信,接受NameNode的指令。为了减轻NameN
32、ode的负担,NameNode上并不永久保存那个DataNode上有那些数据块的信息,而是通过DataNode启动时的上报,来更新NameNode上的映射表。DataNode和NameNode建立连接以后,就会不断地和NameNode保持心跳。心跳的返回其还也包含了NameNode对DataNode的一些命令,如删除数据库或者是把数据块复制到另一个DataNode。应该注意的是:NameNode不会发起到DataNode的请求,在这个通信过程中,它们是严格的客户端/服务器架构。DataNode当然也作为服务器接受来自客户端的访问,处理数据块读/写请求。DataNode之间还会相互通信,执行数据块复制任务,同时,在客户端做写操作的时候,DataNode需要相互配合,保证写操作的一致性。2.1 集群系统工作状态