随着数据量越来越大,在一个操作系统中存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统,HDFS
只是分布式文件管理系统中的一种,通过目录树来定位文件
优点:
- 高容错性,自动保存多个副本,通过增加副本的形式,提升容错性,当某一个副本丢失之后,可以自动恢复
- 适合处理大数据
- 可以构建在大量廉价机器上,通过多副本机制,提高可靠性
缺点:
- 不适合低延时数据访问,如毫秒级的存储
- 无法高效的对大量小文件进行存储,存储大量小文件会占用
NameNode
大量的内存来存储文件目录和块信息,这样不可取因为NameNode
的内存是有限的 - 不支持并发写入
NameNode
Master主管,管理HDFS
名称空间,配置副本策略和块的映射信息,处理客户端的请求
-
NameNode
元数据信息 文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个
文件的块列表。 以及列表中的块与块所在的DataNode
之间的地址映射关系 在内存中加载文件
系统中每个文件和每个数据块的引用关系(文件、block
、datanode
之间的映射信息) 数据会定
期保存到本地磁盘(fsImage
文件和edits
文件) -
NameNode
文件操作NameNode
负责文件元数据的操作DataNode
负责处理文件内容的读写
请求,数据流不经过NameNode
,会询问它跟那个DataNode
联系 -
NameNode
副本 文件数据块到底存放到哪些DataNode
上,是由NameNode
决定的,NN
根
据全局情况做出放置副本的决定 -
NameNode
心跳机制 全权管理数据块的复制,周期性的接受心跳和块的状态报告信息(包
含该DataNode
上所有数据块的列表) 若接受到心跳信息,NameNode
认为DataNode
工作正
常,如果在10分钟后还接受到不到DN
的心跳,那么NameNode
认为DataNode
已经宕机 ,这时候NN
准备要把DN
上的数据块进行重新的复制。 块的状态报告包含了一个DN
上所有数据块的列
表,blocks report
每个1小时发送一次
DataNode
Slave,NameNode
下达命令,DataNode
执行实际的操作,存储了实际数据块,执行数据块的读写操作Secondary NameNode
并非NameNode
的热备,而是辅助NameNode
分担其工作量,定期合并Fsimage
和Edits
,并推送给NameNode
为什么块的大小不能设置太小,也不能设置太大?HDFS
太大,从磁盘传输数据的时间会明显大于定位这个块开始的位置所需的时间,导致程序在处理这块数据时,会非常慢;但如果太小,会增加寻址时间,程序一直在找块开始的位置。总的来说:HDFS
块的大小设置主要取决于磁盘传输速率
FsImage 和 Edits 详解
edits
:存放了客户端最近一段时间的操作日志,客户端对HDFS
进行写文件时会首先被记录在edits
文件中edits
修改时元数据也会更新。如果edits
到达1G大小则合并,如果一直没有达到1G,则设定每1小时Secondary NameNode
合并一次
fsimage
:在HDFS
启动时加载fsimage
的信息,包含了整个HDFS
文件系统的所有目录和文件的信息。NameNode
中关于元数据的镜像, 一般称为检查点, fsimage
存放了一份比较完整的元数据信息,因为fsimage
是NameNode
的完整的镜像, 如果每次都加载到内存生成树状拓扑结构,这是非常耗内存和CPU, 所以一般开始时对NameNode
的操作都放在edits
中,fsimage
内容包含了 NameNode
管理下的所有DataNode
文件及文件block
及block
所在的DataNode
的元数据信息。随着 edits
内容增大, 就需要在一定时间点和fsimage
合并
fsimage 中的文件信息查看
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas
hdfs oiv -i fsimage_0000000000000000864 -p XML -o hello.xml
edits 中的文件信息查看
cd /export/servers/hadoop2.7.5/hadoopDatas/namenodeDatas
hdfs oev -i edits_0000000000000000865-0000000000000000866 -p XML -o myedit.xml
SecondaryNameNode辅助管理fsimage与edits文件
如果所有的更新操作都往fsimage
文件中添加,这样会导致系统运行的十分缓慢, 所以需要SecondaryNameNode
辅助管理fsimage
与edits
文件
-
SecondaryNameNode
通知NameNode
切换editlog
-
SecondaryNameNode
从NameNode
中获得fsimage
和editlog
(通过http
方式) -
SecondaryNameNode
将fsimage
载入内存, 然后开始合并editlog
, 合并之后成为新的fsimage
-
SecondaryNameNode
将新的fsimage
发回给NameNode
-
NameNode
用新的fsimage
替换旧的fsimage
特点
一、完成合并的是
SecondaryNameNode
, 会请求NameNode
停止使用edits
, 暂时将新写操作放入一个新的文件中edits.new
二、SecondaryNameNode
从NameNode
中通过Http GET
获得edits
, 因为要和fsimage
合并, 所以也是通过Http Get
的方式把fsimage
加载到内存, 然后逐一执行具体对文件系统的操作, 与fsimage
合并, 生成新的fsimage
, 然后通过Http POST
的方式把fsimage
发送给NameNode
.NameNode
从Secondary NameNode
获得了fsimage
后会把原有的fsimage
替换为新的fsimage
, 把edits.new
变成edits
. 同时会更新fstime
HDFS 文件写入过程
-
Client
发起文件上传请求, 通过RPC
与NameNode
建立通讯,NameNode
检查目标文件是
否已存在, 父目录是否存在, 返回是否可以上传 -
Client
请求第一个block
该传输到哪些DataNode
服务器上 -
NameNode
根据配置文件中指定的备份数量及机架感知原理进行文件分配, 返回可用的DataNode
的地址如: A, B, C
-Hadoop
在设计时考虑到数据的安全与高效, 数据文件默认在HDFS
上存放三份, 存储
策略为本地一份, 同机架内其它某一节点上一份, 不同机架的某一节点上一份。 -
Client
请求3台DataNode
中的一台A上传数据(本质上是一个RPC
调用,建立pipeline
), A收到请求会继续调用B, 然后B调用C, 将整个pipeline建立完成, 后逐级返回client
-
Client
开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存), 以
packet为单位(默认64K
), A收到一个packet就会传给B, B传给C. A每传一个packet会
放入一个应答队列等待应答 - 数据被分割成一个个packet数据包在pipeline上依次传输, 在pipeline反方向上, 逐个发
送ack
(命令正确应答), 最终由pipeline中第一个DataNode
节点A将pipelineack
发送
给Client
- 当一个block传输完成之后,
Client
再次请求NameNode
上传第二个block到服务 1
HDFS 文件读取过程
-
Client
向NameNode
发起RPC
请求,来确定请求文件block
所在的位置; -
NameNode
会视情况返回文件的部分或者全部block
列表,对于每个block
,NameNode
都会返回含有该block
副本的DataNode
地址; 这些返回的DN
地址,会按照集群拓扑结构得出DataNode
与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client
近的排靠前;心跳机制中超时汇报的DN
状态为STALE
,这样的排靠后; -
Client
选取排序靠前的DataNode
来读取block
,如果客户端本身就是DataNode
,那么将从
本地直接获取数据(短路读取特性); - 底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类
DataInputStream
的read
方法,直到这个块上的数据读取完毕; - 当读完列表的
block
后,若文件读取还没有结束,客户端会继续向NameNode
获取下一
批的block
列表; - 读取完一个
block
都会进行checksum
验证,如果读取DataNode
时出现错误,客户端会
通知NameNode
,然后再从下一个拥有该block
副本的DataNode
继续读。 -
read
方法是并行的读取block
信息,不是一块一块的读取;NameNode
只是返回Client
请
求包含块的DataNode
地址,并不是返回请求块的数据; - 最终读取来所有的
block
会合并成一个完整的最终文件。