简介
作为Hadoop生态中核心的组件,HDFS在Hadoop项目最初就已经存在。HDFS始于 Google 在2003年10月份发表的GFS(Google File System)论文。 它其实就是 GFS 的一个克隆版本。但是经过这些年的发展,HDFS的架构和功能基本固化,并成为一个完善的核心组件。
在如下HDFS的官网中,有对HDFS的详细描述,针对我装的版本(Hadoop 2.7.7):
- HDFS Architecture:
http://hadoop.apache.org/docs/r2.7.7/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
- HDFS User Guide:
http://hadoop.apache.org/docs/r2.7.7/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html
HDFS的概念
HDFS (Hadoop Distributed File System)是分布式文件系统。其为海量的数据提供了存储,它是分布式计算中数据存储管理的基础,为海量日志类大文件的在线存储提供便利。
HDFS是基于流数据模式访问和处理超大文件的需求而开发的,可以运行于廉价的大型服务器集群上。因此,在设计上HDFS把硬件故障作为一种常态来考虑,可以保证在部分硬件发生故障的情况下仍然能够保证文件系统的整体可用性和可靠性。
HDFS提供一次写入、多次读取的机制,数据以块的形式,同时分布存储在不同的物理机器上。在Hadoop 2中,HDFS默认的块大小为128M,HDFS中的文件被分成块存储在若干台DataNode服务器上。
HDFS的特点
HDFS的概念决定了其有如下几个假设与特点:
在HDFS的设计中,硬件故障是常见的,而非特例。所以,HDFS能够快速定位故障,并自动修复故障。
运行在HDFS上的应用是通过流数据模式访问数据集的。HDFS是为了批处理设计的,而不是为了交互式用户使用。HDFS侧重于提高数据访问的吞吐量,而不是降低数据访问的延迟。
HDFS的存储数据量级超大,一般存储在HDFS上的数据量级是GB至TB级的。
HDFS是“一次写入,多次读取”的模型。一旦文件被创建、写入、关闭后不得再改写。这个机制保证了数据的一致性与高数据访问的吞吐量。
- 应用可移动到与数据更近的地方(“Moving Computation is Cheaper than Moving Data”)
去移动计算处理(比如移动一个脚本)要比直接移动数据更便宜,尤其是数据量超大的时候。所以我们更倾向把计算移动到数据附近,而不是把数据移动到计算附近。因此,HDFS提供了界面,让应用可以主动移动到数据的所在地。
- 多硬件与软件平台间的可移植性(Portability Across Heterogeneous Hardware)
HDFS被设计成可以轻易从一个平台移植到另一个平台。所以HDFS能适应很多软件/硬件平台。
HDFS的架构
HDFS采用主从架构(Master/Slave architecture)。在一个HDFS的集群中存在一个NameNode与多个DataNode。
一个NameNode运行在主服务器(Master server)上,负责管理文件系统的命名空间并规范客户端对文件的访问。NameNode可以进行文件系统命名空间的操作,比如打开文件、关闭文件、重命名文件或目录(就像我们日常用电脑那样)。NameNode同时决定了数据块到DataNode的映射关系(Mapping)。
多个DataNode运行在从服务器(Slave server)上,通常在集群中,一个节点对应一个DataNode,负责所在节点上的数据存储。DataNode负责存储与检索数据块、将客户端(client)读/写请求提供给NameNode、按NameNode的指令进行数据块的创建、删除、备份操作。
NameNode与DataNode都是运行在服务器上的软件。服务器一般是在GNU/Linux环境下运行的。HDFS是基于Java语言开发,任何支持Java的机器都支持NameNode与DataNode软件的运行。
下图是官网对HDFS架构的示例图。
文件系统命名空间
HDFS有一个文件系统命名空间,它允许用户数据以文件形式存储。用户或应用可以在文件目录中创建目录或存储文件。HDFS的文件命名空间与我们生活中用电脑操作文件没什么区别。但是HDFS目前没有用户权限与用户额度的定义。
NameNode负责系统文件命名空间的维护。一切修改文件命名空间或其属性的操作都会记录在NameNode中。
数据块(Block)
HDFS被设计成在大集群与跨机器间可靠的存储超大数据。因此,HDFS将每个文件分成有顺序的小数据块(Block),除了最后一块,其余的块都是一样的大小,这些数据块被存在多个DataNode中。
Hadoop 1.x的HDFS默认块大小为64MB,Hadoop2.x的默认块大小为128MB,默认大小可在hdfs-default.xml中dfs.blocksize属性定义,小于一个块大小的文件不会占用整个块的空间。
每个数据块,HDFS默认为其保存3个副本,副本数量可在hdfs-default.xml中dfs.replication属性定义。这样就保证了HDFS的容错性。NameNode负责确定数据块备份的所有决定。NameNode会定期从每个DataNode收到Heartbeat与Blockreport,Heatbeat说明该DataNode运行正常,Blockreport列出了该DataNode中的所有数据块。
HDFS的运行机制
客户端向HDFS写数据
- 客户端通过RPC向NameNode提交写数据请求
- NameNode检查:该文件是否存在,客户端是否有权限写数据。如果客户端可以写入,则为该文件创建一条记录;如果客户端不可以写入,则向客户端抛出异常
- 客户端收到NameNode允许写入通知后,将文件进行切分,分成多个packets,并向NameNode申请Blocks,NameNode返回Blocks列表给客户端
- 客户端收到blocks列表后,客户端将packets写到blocks列表中。当packet写到第一个DataNode完成时,该DataNode会把该分块数据复制到其他DataNode中,默认复制3份。
- 最后一个DataNode成功存储之后,客户端接收到消息,会移除相应的packet,并通知NameNode。NameNode会在内存中的Metadata中添加一条该文件信息的描述,并在edits日志文件中写入一条记录。
- 如果写数据的过程中发现异常,都会在edits日志文件中记录操作。
客户端从HDFS读数据
- 客户端通过RPC向NameNode发起RPC请求
- NameNode返回该文件的元数据信息,包括文件名称,分块ID,主机映射等等。
- 客户端根据元数据信息向最近的DataNode读取block,如果客户端本身是DataNode,那么将直接从本地获取数据,block的读取是同步的,即读完一块block,才可以读另一块block
- 读取完一个block都会仅从checksum验证,如果发现block错误,客户端会通知NameNode,NameNode将会从其他拷贝副本选择一份让客户端继续读取。
HDFS的配置文件与参数
NameNode(hdfs-site.xml)
参数 | 属性值 | 解释 |
dfs.replication | 3 | 默认备份block的数量。如果是伪分布式,设置为1就行了。 |
dfs.namenode.name.dir | 在本地文件系统所在的NameNode的存储空间和持续化处理日志 | 如果这是一个以逗号分隔的目录列表,然后将名称表被复制的所有目录,以备不时需。 |
dfs.blocksize | 134217728 | 默认存储数据块的大小,默认 HDFS块大小为128MB,这里单位是B,128MB=13421772 |
DataNode(hdfs-site.xml)
参数 | 属性值 | 解释 |
dfs.datanode.data.dir | 逗号分隔的一个DataNode上,它应该保存它的块的本地文件系统的路径列表 | 如果这是一个以逗号分隔的目录列表,那么数据将被存储在所有命名的目录,通常在不同的设备。 |
HDFS常用命令
HDFS的操作可以依赖Shell语句。
官网:http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/FileSystemShell.html