HDFS是Hadoop 分布式文件系统,可以运行在通用硬件上、提供流式数据操作、能够处理超大文件的分布式文件系统。HDFS具有高度容错、高吞吐量、容易扩展、高可靠性等特征。
HDFS是一个主/从体系结构的分布式系统,拥有1个Namenode和多个Datanodes,用户可以通过HDFS客户端同Namenode和Datanodes交互以访问文件系统。Namenode是HDFS的Master节点,负责管理文件系统的命名空间,以及数据块到具体Datanode节点的映射等信息
。Datanode一般是一个节点一个,负责管理它所在节点上的存储。
一个文件被分成一个或多个数据块,这些块存储在一组Datanode上
,Datanode以本地文件的形式保存这些数据块以及数据块的校验信息。
高容错性
适合批处理
适合处理大数据
能够处理PB级别的数据
能够处理百万规模以上的文件数量
能够处理10K节点的规模
流式文件访问
可构建在廉价机器上
高延迟问题
存储小文件问题
HDFS文件以数据块形式存储,数据块是HDFS文件处理(读或者写)的最小单元
。由于HDFS文件往往较大,同时为了最小化寻址开销,所以HDFS数据块也更大
,默认是128MB。数据块以文件形式存储在Datanode的磁盘上。
所有文件都会被切分成若干个数据块分布在Datanode上存储。为了实现可靠性,同一个数据块会冗余被分到不同的Datanode上,(一个数据块默认保存3份)。
读操作中,HDFS客户端会首先到Namenode查找HDFS文件包含的数据块的位置信息
,然后根据尾值信息从Datanode读取数据。
写操作中,HDFS客户端也会首先从Namenode申请新的数据块
,然后根据新申请数据块的位置信息建立数据流管道写数据。
Namenode 管理着文件系统的命名空间(namespace),包括文件系统目录树、文件/目录信息以及文件的数据块索引,这些信息以两个文件的形式永久保存
在Namenode的本地磁盘,即命名空间镜像文件和编辑日志文件
。同时还保存着数据块与数据节点的对应关系
,这部分数据不保存在本地磁盘,而是在Namenode启动时动态构建
。HDFS客户端会通过名字节点获取上述信息,之后读写文件。
Namenode是HDFS的单一故障点,Hadoop2.X引入HA。同一个集群配置两个Namenode,Active-Namenode的内存元数据与Standby-Namenode完全同步
。
因为Namenode中保存了数据块与数据节点的对应关系。如果集群文件数量过多,Namenode的内存将成为限制系统横向扩展的瓶颈
。为了解决这个问题,Hadoop2.X引入联邦HDFS机制
(Hadoop Federation)。其允许添加Namenode以实现命名空间的扩展,每个Namenode管理文件系统命名空间的一部分,是一个独立的名空间卷。卷之间相互独立,两两之间不通信,一个Namenode失效了也不会影响其他Namenode所维护的命名空间的可用性
。
Datanode会根据HDFS客户端请求或者Namenode调度将新的数据块写入本地存储,或者读出本地存储上保存的数据块。
作为从节点,Datanode会不断地向Namenode发送心跳、数据块汇报、缓存汇报,Namenode会通过心跳、数据块汇报、缓存汇报的响应
向Datanode发送指令,Datanode会执行这些指令。
由于HDFS作为一个分布式文件系统,某些流程非常复杂,常常涉及Datanode、Namenode、Client三者之间的配合以及相互调用。为了降低耦合,HDFS将这些节点间的调用抽象成不同的接口。
Hadoop RPC接口:HDFS基于Hadoop RPC框架实现的接口
流式接口: HDFS基于TCP或者HTTP实现的接口
浅看,未深入源码
DFSInputSteam
对象用于读取数据块。HDFS文件起始位置数据块的位置信息
,Namenode返回的数据块的存储位置是按照与客户端的距离远近排序的
,所以可以返回一个最优
的Datanode节点,与这个节点建立连接读取数据块.在达到一个数据块末尾时,DFSInputStream会再次获取文件下一个数据块的位置信息,并建里这个新的数据块的最优节点之间的连接。
异常情况:
读数据时,存储这个数据块的Datanode出现异常,无法读取数据。DFSInputStream会切换到另一个保存了这个数据块的数据节点读取数据
。
数据块的应答包中不仅包含了数据,还包含校验值,HDFS客户端收到数据应答包时,会校验数据
。如果出现校验错误,也就是数据节点上的这个数据块副本出现了损坏,Client会向Namenode汇报这个损坏的数据块副本
,同时DFSInputStream会尝试从其他的数据节点读取这个数据块
。
空文件
,并将创建新文件的操作记录到editlog中,并返回一个DFSOutputStream
对象,用于执行写操作。申请一个新的数据块
,并返回一个LocatedBlock
对象,这个对象保存了存储这个数据块的所有Datanode的位置信息
。获得了数据流管道中所有Datanode的信息后,DFSOutputStream既可以建立数据流管道写数据块了。缓存在数据流
中,之后被切成数据包
(packet)通过管道发送到所有Datanode
。每个packet都有个确认包
,确认包会逆序通过管道回到输出流。输出流确认了所有Datanode都写入这个packet后,就会从缓存队列删除这个packet
。通知Namenode提交这个文件中的所有数据块
。 对于Datanode,当Datanode成功地接收一个新的数据块时
,Datanode会向Namenode汇报,Namenode会更新内存中的数据块与数据节点的对应关系
异常情况:
客户端写文件是,数据流管道中的Datanode故障
,有如下故障恢复操作:
输出流中缓存的没有确认的packet会重新加入发送队列
。输出流会为数据块申请一块新的时间戳,用新时间戳重新建立数据流管道
。这保证故障Datanode上的数据块的时间戳会过期
,故障恢复之后,由于数据块的时间戳与Namenode元数据中的不匹配而被删除,保证了集群中所有数据块的正确性。故障Datanode点会从Datanode列表中删除,通知Namenode分配新的Datanode到数据流管道中
。接下来输出流会将新分配的Datanode添加到数据流管道中,并使用新的时间戳重新建立数据流管道。由于新添加的Datanode上并没有存储这个新的数据块,HDFS客户端会通知数据流管道中的一个Datanode复制这个数据块到新的Datanode上
。数据流管道重新建立之后,输出流会更新Namenode中的元数据
。故障恢复完成,客户端可以完成后续的写操作。 追加写指打开一个已有文件并执行追加写操作,和写流程很类似,只不过在初始建立数据流管道时有些不同。
获取文件租约
。 Datanode启动后与Namenode的交互主要包括三个部分:握手;注册;快汇报以及缓存汇报
Datanode启动过程
Datanode工作过程
定期
将执行的操作记录在editlog
中,并写入JNS的多数节点中
。Standby 会一直监听JNS上editlog的变化,如果有改动,就会读取editlog并与当前的命名空间合并。所有的
editlog并与命名空间合并,然后才切换到Active状态。同时向这两个Namenode发送心跳以及快汇报信息
。这样就完全同步了,也就可以实现热备
。RPC(Remote Procedure CallProtocol,远程过程调用协议),允许本地程序像调用本地方法一样调用远程机器上应用程序提供的服务。
《Hadoop 2.X HDFS源码剖析》
深入理解HDFS
HDFS——写文件中的异常处理
HadoopRPC源码解析