设计目标

  • 自动快速检测应对硬件错误

  • 流式访问数据

  • 转移计算比转移数据本身更划算

  • 简单一致性模型

  • 异构平台的可移植性

![HDFS体系结构][1]

HDFS采用了master-slave架构,一个HDFS集群由一个master节点(NameNode)和若干个slave节点(DataNode)组成

  • NameNode
    NameNode是一个中心服务器,维护着文件系统树以及整棵树内的所有文件目录,负责整个数据集群的管理

  • DataNode
    DataNode分布在不同的机架上,在客户端或NameNode的调度下存储并检索数据块并且定期向NameNode发送它所存储的块的列表,客户端通过NameNode和DataNode的交互访问文件系统,它联系NameNode以获取文件的源数据而真正的IO操作则是直接和DataNode进行交互,为了应对节点故障数据块在不同的DataNode之间保存了多个副本,默认情况下每个数据块都保存了3个副本,其中2个副本存放在同一个机架的2个不同节点上,另一个副本存在不同机架的节点上

基本概念

  • 机架
    HDFS集群由分布在多个机架上的大量DataNode组成,不同机架节点之间通过交换机通信,HDFS通过机架感知策略使NameNode能够确定每个DataNode所属的机架ID,使用副本存放策略改进数据的可靠性,可用性和网络带宽的利用率

  • 数据块(block)
    它是HDFS存储的最基本单元,默认的数据块大小为64M,用户可以自行设置这个属性

  • 元数据:镜像文件(Fsimage) + 日志文件(EditLog)
    元数据是HDFS文件系统中文件和目录的属性信息,HDFS实现的时候采用的镜像文件和日志文件的备份机制,对于文件来讲镜像文件中包含的信息主要包括:修改时间,访问时间,数据块大小以及组成一个文件的数据块的存储位置等信息,对于目录来讲镜像文件主要包含的信息包括:修改时间,访问控制权限等信息.日志文件中记录的事HDFS中所有的更新操作.在HDFS中创建一个文件,NameNode就会在日志文件中插入一条记录来表示,同样的修改文件的副本系数也将会在日志文件中有所体现.NameNode启动的时候会把镜像文件和日志文件的内容在内存中合并,把内存中的元数据更新到最新状态

  • 用户数据
    HDFS存储的大部分都是用户数据,以数据块的形式存储在多个DataNode上

主从节点的通信

![主从节点的通信][2]

HDFS中NameNode和DataNode之间使用TCP协议进行通信,DataNode每3秒钟向NameNode发送一个心跳,通过心跳机制DataNode向NameNode报告自己处于存活状态,并且每10次心跳之后会向NameNode发送一次数据块报告,告诉自己存储的数据块信息,通过这些信息NameNode能够重建元数据并确保每个数据块有足够的副本

写数据流程

![写数据流程][3]

首先客户端通过open函数打开分布式文件系统,分布式文件系统通过远程过程调用访问NameNode,在文件系统中创建一个新的文件,NameNode首先会确定该文件不存在并且客户端具有创建文件的权限,然后创建新文件.客户端通过文件系统数据输出流开始写入数据,FSDataOuputStream将数据分成块写入数据队列,DataStreamer负责处理数据队列,它的任务是根据数据队列要求NameNode分配适合的DataNode来存储数据副本,每个数据块默认复制3块,然后将数据块写入第一个DataNode,第一个DataNode将数据块发送给第二个DataNode,第二个DataNode又将收到的数据块发送给第三个DataNode.这三个DataNode存储的都是同一个数据块的三个副本.FSDataOuputStream为发出去的数据块维护了ACK队列等待收到数据的DataNode告知数据已经写入成功,当客户端数据写入成功后,调用FSDataOuputStream的close函数通知NameNode写入完毕

读数据流程

![读数据流程][4]

首先客户端调用文件系统的open函数打开文件,分布式文件系统使用远程过程调用访问NameNode得到文件的数据块信息,杜宇每一个数据块,NameNode返回存储该数据块的DataNode的地址,客户端调用FSDataInputStream的read函数开始读取数据,FSDataInputStream向距离最近的保存目标文件第一个数据块的DataNode发起连接,建立连接的DataNode向客户端返回数据块的内容,当第一个数据块读取完毕后FSDataInputStream关闭和刚才的DataNode
建立的连接,然后向最近的保存目标下一个数据块的DataNode发起连接,当目标数据读取完成后调用FSDataInputStream的close函数.在读取数据的过程中如果客户端与DataNode的通信出现错误就会尝试向存储目标数据块副本的DataNode发起连接,发生错误的DataNode将被记录,以后不在会向改节点发起连接