随着数据量越来越大,在一个操作系统中存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统,HDFS只是分布式文件管理系统中的一种,通过目录树来定位文件

优点:

  • 高容错性,自动保存多个副本,通过增加副本的形式,提升容错性,当某一个副本丢失之后,可以自动恢复
  • 适合处理大数据
  • 可以构建在大量廉价机器上,通过多副本机制,提高可靠性

缺点:

  • 不适合低延时数据访问,如毫秒级的存储
  • 无法高效的对大量小文件进行存储,存储大量小文件会占用NameNode大量的内存来存储文件目录和块信息,这样不可取因为NameNode的内存是有限的
  • 不支持并发写入

NameNode Master主管,管理HDFS名称空间,配置副本策略和块的映射信息,处理客户端的请求

  • NameNode元数据信息 文件名,文件目录结构,文件属性(生成时间,副本数,权限)每个
    文件的块列表。 以及列表中的块与块所在的DataNode之间的地址映射关系 在内存中加载文件
    系统中每个文件和每个数据块的引用关系(文件、blockdatanode之间的映射信息) 数据会定
    期保存到本地磁盘(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分担其工作量,定期合并FsimageEdits,并推送给NameNode

为什么块的大小不能设置太小,也不能设置太大?
HDFS 太大,从磁盘传输数据的时间会明显大于定位这个块开始的位置所需的时间,导致程序在处理这块数据时,会非常慢;但如果太小,会增加寻址时间,程序一直在找块开始的位置。总的来说:HDFS 块的大小设置主要取决于磁盘传输速率

FsImage 和 Edits 详解

edits:存放了客户端最近一段时间的操作日志,客户端对HDFS进行写文件时会首先被记录在edits文件中edits修改时元数据也会更新。如果edits到达1G大小则合并,如果一直没有达到1G,则设定每1小时Secondary NameNode合并一次

fsimage :在HDFS启动时加载fsimage的信息,包含了整个HDFS文件系统的所有目录和文件的信息。NameNode中关于元数据的镜像, 一般称为检查点, fsimage存放了一份比较完整的元数据信息,因为fsimageNameNode的完整的镜像, 如果每次都加载到内存生成树状拓扑结构,这是非常耗内存和CPU, 所以一般开始时对NameNode的操作都放在edits中,fsimage内容包含了 NameNode管理下的所有DataNode文件及文件blockblock 所在的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辅助管理fsimageedits文件

  1. SecondaryNameNode通知NameNode切换editlog
  2. SecondaryNameNodeNameNode中获得fsimageeditlog(通过http方式)
  3. SecondaryNameNodefsimage载入内存, 然后开始合并editlog, 合并之后成为新的fsimage
  4. SecondaryNameNode将新的fsimage发回给NameNode
  5. NameNode用新的fsimage替换旧的fsimage

特点

一、完成合并的是SecondaryNameNode, 会请求NameNode停止使用edits, 暂时将新写操作放入一个新的文件中edits.new 二、SecondaryNameNodeNameNode中通过Http GET获得edits, 因为要和fsimage合并, 所以也是通过Http Get的方式把fsimage加载到内存, 然后逐一执行具体对文件系统的操作, 与fsimage合并, 生成新的fsimage, 然后通过Http POST的方式把fsimage发送给NameNode. NameNodeSecondary NameNode获得了fsimage后会把原有的fsimage替换为新的fsimage, 把edits.new变成edits. 同时会更新fstime

HDFS 文件写入过程

  1. Client 发起文件上传请求, 通过 RPCNameNode 建立通讯, NameNode 检查目标文件是
    否已存在, 父目录是否存在, 返回是否可以上传
  2. Client 请求第一个block该传输到哪些DataNode服务器上
  3. NameNode根据配置文件中指定的备份数量及机架感知原理进行文件分配, 返回可用的
    DataNode的地址如: A, B, C
    -Hadoop在设计时考虑到数据的安全与高效, 数据文件默认在HDFS上存放三份, 存储
    策略为本地一份, 同机架内其它某一节点上一份, 不同机架的某一节点上一份。
  4. Client请求3台DataNode中的一台A上传数据(本质上是一个RPC调用,建立pipeline
    ), A收到请求会继续调用B, 然后B调用C, 将整个pipeline建立完成, 后逐级返回client
  5. Client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存), 以
    packet为单位(默认64K), A收到一个packet就会传给B, B传给C. A每传一个packet会
    放入一个应答队列等待应答
  6. 数据被分割成一个个packet数据包在pipeline上依次传输, 在pipeline反方向上, 逐个发
    ack(命令正确应答), 最终由pipeline中第一个DataNode节点A将pipelineack发送
    Client
  7. 当一个block传输完成之后, Client再次请求NameNode上传第二个block到服务 1

HDFS 文件读取过程

  1. ClientNameNode发起RPC请求,来确定请求文件block所在的位置;
  2. NameNode会视情况返回文件的部分或者全部block列表,对于每个blockNameNode都会返回含有该block副本的DataNode地址; 这些返回的DN地址,会按照集群拓扑结构得出DataNode与客户端的距离,然后进行排序,排序两个规则:网络拓扑结构中距离Client近的排靠前;心跳机制中超时汇报的DN状态为STALE,这样的排靠后;
  3. Client选取排序靠前的DataNode来读取block,如果客户端本身就是DataNode,那么将从
    本地直接获取数据(短路读取特性);
  4. 底层上本质是建立Socket Stream(FSDataInputStream),重复的调用父类
    DataInputStreamread方法,直到这个块上的数据读取完毕;
  5. 当读完列表的block后,若文件读取还没有结束,客户端会继续向NameNode获取下一
    批的block列表;
  6. 读取完一个block都会进行checksum验证,如果读取DataNode时出现错误,客户端会
    通知NameNode,然后再从下一个拥有该block副本的DataNode继续读。
  7. read方法是并行的读取block信息,不是一块一块的读取;NameNode只是返回Client
    求包含块的DataNode地址,并不是返回请求块的数据;
  8. 最终读取来所有的block会合并成一个完整的最终文件。