1.HDFS简介
正如其名,HDFS(Hadoop Distribution File System)
是一个分布式文件系统,它在商用服务器集群中存储文件,用来存储和快速访问大文件与大数据集。这是一个可扩展、可容错的系统。
HDFS
的优点:
- 兼容廉价的硬件设备
- 流数据读写
- 大数据集
- 简单的文件模型
- 强大的跨平台模型
HDFS
的局限性:
- 不适合低延迟数据访问
- 无法高效存储大量小文件
- 不支持多用户写入及任意修改文件
2.HDFS相关概念
2.1 块结构
HDFS
是一个块结构的文件系统。正像Linux文件系统那样,HDFS
把文件分成固定大小的块通常叫做分块或者分片,每个快作为独立的单元进行存储。默认的块大小为64MB,但是可以配置。我们所熟悉的普通文件系统的块一般只有几千字节,从这个块的大小清楚的看到,HDFS
不是用来存储小文件的,这样做的好处就是最小化寻址开销。HDFS
采用抽象的块概念可以带来以下几个明显的好处:
- 支持大规模文件存储:文件以块为单位进行存储,一个大规模文件可以被分拆成若干个文件块,不同的文件块可以被分发到不同的节点上,因此,一个文件的大小不会受到单个节点的存储容量的限制,可以远远大于网络中任意节点的存储容量。
- 简化系统设计:首先,大大简化了存储管理,因为文件块大小是固定的,这样就可以很容易计算出一个节点可以存储多少文件块;其次,方便了元数据的管理,元数据不需要和文件块一起存储,可以由其他系统负责管理元数据。
- 适合数据备份:每个文件块都可以冗余存储到多个节点上,大大提高了系统的容错性和可用性。
2.2 HDFS主要组件的功能
一个HDFS集群包含两种类型的节点:NameNode
和DataNode
。
NameNode | DataNode |
---|---|
存储元数据 | 存储文件内容 |
元数据保存在内存中 | 文件内容保存在磁盘 |
保存文件,block,datanode之间的映射关系 | 维护了block id到datanode本地文件的映射关系 |
NameNode
周期性接收来自HDFS
集群中DataNode
的两种类型的消息,分别叫做心跳消息和块报告消息。DataNode
发送一个心跳消息来告知NameNode
工作正常。块报告消息包含一个DataNode
上所有数据块的列表。
2.3名称节点 NameNode
•在HDFS中,名称节点(NameNode
)负责管理分布式文件系统的命名空间(Namespace
),保存了两个核心的数据结构,即FsImage
和EditLog
。
- •
FsImage
用于维护文件系统树以及文件树中所有的文件和文件夹的元数据。 - •操作日志文件
EditLog
中记录了所有针对文件的创建、删除、重命名等操作。
NameNode
记录了每个文件中各个块所在数据节点的位置信息。
FSImage文件
FsImage
文件包含文件系统中所有目录和文件inode的序列化形式。每个inode
是一个文件或目录的元数据的内部表示,并包含此类信息:文件的复制等级、修改和访问时间、访问权限、块大小以及组成文件的块。对于目录,则存储修改时间、权限和配额元数据。
FsImage
文件没有记录文件包含哪些块以及每个块存储在哪个数据节点。而是由名称节点把这些映射信息保留在内存中,当数据节点加入HDFS
集群时,数据节点会把自己所包含的块列表告知给名称节点,此后会定期执行这种告知操作,以确保名称节点的块映射是最新的。
NameNode的启动
在名称节点启动的时候,它会将FsImage
文件中的内容加载到内存中,之后再执行EditLog
文件中的各项操作,使得内存中的元数据和实际的同步,存在内存中的元数据支持客户端的读操作。
一旦在内存中成功建立文件系统元数据的映射,则创建一个新的FsImage
文件和一个空的EditLog
文件。
名称节点起来之后,HDFS
中的更新操作会重新写到EditLog
文件中,因为FsImage
文件一般都很大(GB级别的很常见),如果所有的更新操作都往FsImage
文件中添加,这样会导致系统运行的十分缓慢,但是,如果往EditLog
文件里面写就不会这样,因为EditLog
要小很多。每次执行写操作之后,且在向客户端发送成功代码之前,edits
文件都需要同步更新。
2.4 数据节点DataNode
数据节点(DataNode
)是分布式文件系统HDFS的工作节点,负责数据的存储和读取,会根据客户端或者名称节点的调度来进行数据的存储和检索,并且向名称节点定期发送自己所存储的块列表。每个数据节点中的数据会保存在各自节点的本地Linux文件系统中。下面图是数据节点的存储目录:
- current目录:保存着HDFS文件系统中的数据块,这些数据块是成功提交到HDFS的数据块。
- in_use.lock:表明目录已经被使用,停止数据节点,该文件会消失,通过in_use.lock文件,数据节点可以保证独自占用该目录,防止两个数据节点示例共享一个目录,造成混乱。
2.5 第二名称节点SecondaryNameNode
NameNode
运行期间EditLog
不断变大的问题?
在NameNode
运行期间,HDFS
的所有更新操作都是直接写到EditLog
中,久而久之,EditLog
文件将变得很大。虽然这对名称节点运行时候是没有什么明显影响的,但是,当名称节点重启的时候,名称节点需要先将FsImage
里面的所有内容映像到内存中,然后再一条一条地执行EditLog
中的记录,当EditLog
文件非常大的时候,会导致名称节点启动操作非常慢,而在这段时间内HDFS系统处于安全模式,一直无法对外提供写操作,影响了用户的使用。
为了有效解决EditLog
逐渐变大带来的问题,HDFS提供的解决方案是SecondaryNameNode
第二名称节点,并且具有两个功能:
- 1、可以完成
Editlog
与FsImage
的合并操作,减少Editlog
文件大小,缩短名称节点重启时间; - 2、可以作为名称节点的“检查点”,保存名称节点中的元数据信息。
SecondaryNameNode
一般是单独运行在一台机器上(Master)。
SecondaryNameNode的工作情况:
- 1、
SecondaryNameNode
会定期和NameNode
通信,请求其停止使用EditLog
文件,暂时将新的写操作写到一个新的文件edit.new上来,这个操作是瞬间完成,上层写日志的函数完全感觉不到差别; - 2、
SecondaryNameNode
通过HTTP GET
方式从NameNode
上获取到FsImage
和EditLog
文件,并下载到本地的相应目录下; - 3、
SecondaryNameNode
将下载下来的FsImage
载入到内存,然后一条一条地执行EditLog
文件中的各项更新操作,使得内存中的FsImage
保持最新;这个过程就是EditLog
和FsImage
文件合并; - 4、
SecondaryNameNode
执行完(3)操作之后,会通过post
方式将新的FsImage
文件发送到NameNode
节点上; - 5、
NameNode
将从SecondaryNameNode
接收到的新的FsImage
替换旧的FsImage
文件,同时将edit.new
替换EditLog
文件,通过这个过程EditLog
就变小了。
3.HDFS体系结构
HDFS采用了主从(Master/Slave)结构模型,一个HDFS集群包括一个名称节点和若干个数据节点。名称节点作为中心服务器,负责管理文件系统的命名空间及客户端对文件的访问。集群中的数据节点一般是一个节点运行一个数据节点进程,负责处理文件系统客户端的读取请求,在名称节点的统一调度下进行数据块的创建、删除和复制等操作。每个数据节点的数据实际上保存在本地Linux文件系统中的。每个数据节点会周期性向名称节点发送“心跳”信息,报告自己的状态,没有按时发送心跳信息的数据节点会被标记为“宕机”,不会再给它分配任何IO请求。
HDFS是一个部署在集群上的分布式文件系统,因此,很多数据需要通过网络进行传输。所有的HDFS通信协议都是构建在TCP/IP
协议基础之上的。
- 客户端通过一个可配置的端口向名称节点主动发起TCP连接,并使用客户端协议与名称节点进行交互。
- 名称节点和数据节点之间则使用数据节点协议进行交互。
- 客户端与数据节点的交互是通过RPC(Remote Procedure Call)来实现的。在设计上,名称节点不会主动发起RPC,而是响应来自客户端和数据节点的RPC请求。
4. HDFS存储原理
4.1 冗余数据保存
作为一个分布式文件系统,为了保证系统的容错性和可用性,HDFS采用了多副本方式对数据进行冗余存储,通常一个数据块的多个副本会被分布到不同的数据节点上。这种多副本方式具有以下几个优点:
- 1、加快数据传输速度
- 2、容易检查数据错误
- 3、保证数据可靠性
例如,数据块1被分别存放到数据节点A和C,数据块2被存放在数据节点A和B上。
4.2 数据存取策略
4.2.1 数据存放
为了提高数据的可靠性与系统的可用性,以及充分利用网络带宽,HDFS采用了以机架(RACK)为基础的数据存放策略。HDFS默认每个数据节点都是在不用的机架上,这种方法会存在一个缺点:
- 在写入数据的时候不能充分利用同一个机架内部机器之间的带宽。(同一个机架中的不同机器之间的通信要比不同机架之间机器的通信带宽大)
但是和这种缺点相比,也有很多显著的优点:
- 1、可以获得很高的数据可靠性,即使一个机架发生故障,位于其他机架上的数据副本仍然是可以用的;
- 2、在读取数据的时候,可以在多个机架上并行读取数据,大大提高了数据读取速度;
- 3、可以更容易地实现系统内部负载均衡和错误处理。
问题:什么叫做机架(RACK)?
HDFS默认的冗余复制因子是3,每个文件块会被同时保存到3个地方,其中有两份副本放在同一个机架的不同机器上面,第三个副本放在不同机架的机器上面,这样既可以保证机架发生异常时的数据恢复,也可以提高读写性能。一般而言,HDFS副本的放置策略如下图:
4.2.2 数据读取
HDFS提供了一个API可以确定一个数据节点所属的机架ID,客户端也可以调用API获取自己所属的机架ID。当客户端读取数据时,从名称节点获得数据块不同副本的存放位置列表,列表中包含了副本所在的数据节点,可以调用API来确定客户端和这些数据节点所属的机架ID,当发现某个数据块副本对应的机架ID和客户端对应的机架ID相同时,就优先选择该副本读取数据,如果没有发现,就随机选择一个副本读取数据。
4.2.3 数据复制
HDFS的数据复制采用流水线复制的策略,大大提高了数据复制过程的效率。
- 1、当客户端要往HDFS中写入一个文件时,这个文件会首先被写入本地,并被切分若干个块,每个块的大小是由HDFS的设定值来决定的。
- 2、每个块都向HDFS集群中的名称节点发起写请求,名称节点会根据系统中各个数据节点的使用情况,选择一个数据节点列表返回给客户端。
- 3、然后客户端就把数据首先写入列表中的第一个数据节点,同时把列表传给第一个数据节点。当第一个数据节点接收到4KB的数据的时候,写入本地,并且向列表中的第二个数据节点发起连接请求;
- 4、当第二个数据节点接收到4KB数据的时候,写入本地,并且向列表中的第三个数据节点发起连接请求;
- 5、依次类推,列表中的多个数据节点形成一条数据复制的流水线。最后,当文件写完的时候,数据复制也同时完成。
4.3 数据错误与恢复
4.3.1 名称节点出错
名称节点保存了所有的元数据信息,其中,最核心的两个数据结构是FSImage
和Editlog
,如果这两个文件发生损坏,那么整个HDFS实例将失效。因此,HDFS设置了备份机制,把这些核心文件同步复制到备份服务器SecondaryNameNode
上。当名称节点出错时,就可以根据备份服务器SecondaryNameNode
中FSImage
和Editlog
数据进行恢复。
4.3.2 数据节点出错
每个数据节点定期会向名称节点发送“心跳”信息,向名称节点报告自己的状态。当数据节点发生故障,或者网络发生断网时,名称节点就无法收到来自一些数据节点的心跳信息,这时,这些数据节点就会被标记为“宕机”,节点上面的所有书都会被标记为“不可读”,名称节点不会给它们发送任何IO请求。
4.3.3 数据出错
网络传输和磁盘错误等因素会造成数据错误。客户端在读取数据后,会采用MD5
和SHA1
对数据块进行校验,以确定读取到正确的数据。
- 1、在文件被创建时,客户端就会对每个文件块进行信息摘录,并把这些信息写入同一个路径的隐藏文件里面;
- 2、当客户端读取文件的时候,会先读取该信息文件,然后利用该信息文件对每个读取的数据块进行校验;
- 3、如果校验出错,客户端就会请求到另外一个数据节点读取该文件块,并且向名称节点报告这个文件块有错误,名称节点会定期检查并且重新复制这个块。
5. HDFS数据读写过程
5.1 读取
当一个客户端应用想要读取一个文件时,它首先访问NameNode
。NameNode
以组成文件的所有文件块的位置来响应。块的位置标识了持有对应文件块数据的DataNode
。客户端紧接着直接向DataNode发送读请求,以获取每个文件块。NameNode
不参与从DataNode
到客户端的实际数据传输过程。
5.2 写入
当客户端应用想要写数据到HDFS文件时,它首先访问NameNode并要求它在HDFS命名空间中创建一个新的条目。NameNode会检查同名文件是否已存在以及客户端是否有权限来创建新文件。
- 接下来,客户端应用请求NameNode为文件的第一个块选择DataNode。它会在所持有块的复制节点之间创建一个管道,并把数据块发送到管道中第一个DataNode。
- 第一个DataNode在本地存储数据块,然后把它转发给第二个DataNode。第二个DataNode也在本地存储相应数据块,并把它装发给第三个DataNode。
- 在所有委派的DataNode上都存储第一个文件块之后,客户端请求NameNode为第二个块分配DataNode。这个过程持续进行,直到所有文件块都已经在DataNode上存储。最后,客户端告知NameNode文件写操作已完成。
参考资料
http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html