一、HDFS简介
HDFS全称是Hadoop Distributed System。HDFS是为以流的方式存取大文件而设计的。适用于几百MB,GB以及TB,并写一次读多次的场合。而对于低延时数据访问、大量小文件、同时写和任意的文件修改,则并不是十分适合。
HDFS(Hadoop Distributed File System)默认的最基本的存储单位是64M的数据块。
和普通文件系统相同的是,HDFS中的文件是被分成64M一块的数据块存储的。
不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。
HDFS包括元数据节点(NameNode)、数据节点(DataNode)
元数据节点用来管理文件系统的命名空间 其将所有的文件和文件夹的元数据保存在一个文件系统树中。 这些信息也会在硬盘上保存成以下文件:命名空间镜像(namespace image)及修改日志(edit log) 其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而这些信息并不存储在硬盘上,而是在系统启动的时候从数据节点收集而成的。 数据节点是文件系统中真正存储数据的地方。 客户端(client)或者元数据信息(namenode)可以向数据节点请求写入或者读出数据块。 其周期性的向元数据节点回报其存储的数据块信息。 从元数据节点(secondary namenode) 从元数据节点并不是元数据节点出现问题时候的备用节点,它和元数据节点负责不同的事情。 其主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。 合并过后的命名空间镜像文件也在从元数据节点保存了一份,以防元数据节点失败的时候,可以恢复简单地说,元数据节点存放的为对数据的描述,即哪些数据存在哪一个数据节点上,及其他一些数据自身的特征;数据节点为具体存放数据的地方;从数据节点可以粗略理解为备用节点,虽然它还有其他功能。
二、NameNode与secondary namenode
当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit log) namenode在内存中保存了文件系统的元数据信息。在记录了修改日志后,namenode则修改内存中的数据结构。 每次的写操作成功之前,修改日志都会同步(sync)到文件系统。 fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpoint,它是一种序列化的格式,并不能够在接修改。 同数据的机制相似,当namenode失败时,则最新checkpoint的元数据信息从fsimage加载到内存中,然后逐一重新执行中的操作。 secondary namenode就是用来帮助namenode将内存中的元数据信息checkpoint到硬盘上的 checkpoint的过程如下: 1.secondary namenode通知namenode生成新的日志文件,以后的日志都写到新的日志文件中。 2.secondary namenode用http getsecondary namenode获得fsimage文件及旧的日志文件。 3.secondary namenode将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。 4.secondary namenode将新的fsimage文件用http post传回namenode 5.namenode可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),然后更新fstime文件,写入此次checkpoint的时间。 这样namenode中的fsimage文件保存了最新的checkpoint的元数据信息,日志文件也重新开始,不会变的很大了。
三、hdfs读写数据流程
3.1.读数据流程
hdfs读取数据的详细过程如下:
客户端(client)用FileSystem的open()函数打开文件 DistributedFileSystem用RPC调用元数据节点,得到文件的数据块信息。 对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。 DistributedFileSystem返回FSDataInputStream给客户端,用来读取数据。 客户端调用stream的read()函数开始读取数据。 DFSInputStream连接保存此文件第一个数据块的最近的数据节点。 Data从数据节点读到客户端(client) 当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。 当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。 在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。 失败的数据节点将被记录,以后不再连接。忽略掉细节概括起来就是先会请求namenode,从namenode获取数据的信息(存储在哪些节点),
然后选择最近的datanode节点读取数据,然后将从各个节点读取来的信息合并成一个完整的文件。如下图:
3.2.写数据流程
详细过程如下:
客户端调用create()来创建文件 DistributedFileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件。 元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。 DistributedFileSystem返回DFSOutputStream,客户端用于写数据。 客户端开始写入数据,DFSOutputStream将数据分成块,写入data queue。 Data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。 如果数据节点在写入的过程中失败: 关闭pipeline,将ack queue中的数据块放入data queue的开始。 当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。 失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。 元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。 当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。忽略细节后大体流程即为:
1.向namenode请求上传文件
2.namenode响应后,客户端请求上传一个块(block)
3.namenode相应一个datanode
4.客户端向该DataNode发送数据,以packet为单位进行传输,每个DataNode之间建立pipeline通道,同时向所有的DataNode上传数据。即第一个数据节点将它接收到的一部分数据块发送给第二个数据节点。第二个数据节点将其接收到的一部分数据发送给第三个数据节点。
如下图所示:
参考:http://www.cnblogs.com/forfuture1978/archive/2010/03/14/1685351.html