摘要: 概述:HDFS即Hadoop Distributed File System分布式文件系统,它的设计目标是把超大数据集存储到分布在网络中的多台普通商用计算机上,而且可以提供高可靠性和高吞吐量的服务。分布式文件系统要比普通磁盘文件系统复杂,由于它要引入网络编程,分布式文件系统要容忍...编程
概述:HDFS即Hadoop Distributed File System分布式文件系统,它的设计目标是把超大数据集存储到分布在网络中的多台普通商用计算机上,而且可以提供高可靠性和高吞吐量的服务。分布式文件系统要比普通磁盘文件系统复杂,由于它要引入网络编程,分布式文件系统要容忍节点故障也是一个很大的挑战。安全
HDFS主要由3个组件构成,分别是NameNode、SecondaryNameNode和DataNode,HSFS是以master/slave模式运行的,其中NameNode、SecondaryNameNode 运行在master节点,DataNode运行slave节点。markdown
磁盘数据块是磁盘读写的基本单位,与普通文件系统相似,hdfs也会把文件分块来存储。hdfs默认数据块大小为64MB,磁盘块通常为512B,hdfs块为什么如此之大呢?块增大能够减小寻址时间与文件传输时间的比例,若寻址时间为10ms,磁盘传输速率为100MB/s,那么寻址与传输比仅为1%。固然,磁盘块太大也很差,由于一个MapReduce一般以一个块做为输入,块过大会致使总体任务数量太小,下降做业处理速度。网络
数据块是存储在DataNode中的,为了可以容错数据块是以多个副本的形式分布在集群中的,副本数量默认为3,后面会专门介绍数据块的复制机制。架构
hdfs按块存储还有以下好处:并发
当一个客户端请求一个文件或者存储一个文件时,它须要先知道具体到哪一个DataNode上存取,得到这些信息后,客户端再直接和这个DataNode进行交互,而这些信息的维护者就是NameNode。负载均衡
NameNode管理着文件系统命名空间,它维护这文件系统树及树中的全部文件和目录。NameNode也负责维护全部这些文件或目录的打开、关闭、移动、重命名等操做。对于实际文件数据的保存与操做,都是由DataNode负责。当一个客户端请求数据时,它仅仅是从NameNode中获取文件的元信息,而具体的数据传输不须要通过NameNode,是由客户端直接与相应的DataNode进行交互。tcp
NameNode保存元信息的种类有:分布式
须要注意的是,NameNode元信息并不包含每一个块的位置信息,这些信息会在NameNode启动时从各个DataNode获取并保存在内存中,由于这些信息会在系统启动时由数据节点重建。把块位置信息放在内存中,在读取数据时会减小查询时间,增长读取效率。NameNode也会实时经过心跳机制和DataNode进行交互,实时检查文件系统是否运行正常。不过NameNode元信息会保存各个块的名称及文件由哪些块组成。oop
通常来讲,一条元信息记录会占用200byte内存空间。假设块大小为64MB,备份数量是3 ,那么一个1GB大小的文件将占用16*3=48个文件块。若是如今有1000个1MB大小的文件,则会占用1000*3=3000个文件块(多个文件不能放到一个块中)。咱们能够发现,若是文件越小,存储同等大小文件所须要的元信息就越多,因此,Hadoop更喜欢大文件。
在NameNode中存放元信息的文件是 fsimage。在系统运行期间全部对元信息的操做都保存在内存中并被持久化到另外一个文件edits中。而且edits文件和fsimage文件会被SecondaryNameNode周期性的合并(合并过程会在SecondaryNameNode中详细介绍)。
运行NameNode会占用大量内存和I/O资源,通常NameNode不会存储用户数据或执行MapReduce任务。
为了简化系统的设计,Hadoop只有一个NameNode,这也就致使了hadoop集群的单点故障问题。所以,对NameNode节点的容错尤为重要,hadoop提供了以下两种机制来解决:
DataNode是hdfs中的worker节点,它负责存储数据块,也负责为系统客户端提供数据块的读写服务,同时还会根据NameNode的指示来进行建立、删除、和复制等操做。此外,它还会经过心跳按期向NameNode发送所存储文件块列表信息。当对hdfs文件系统进行读写时,NameNode告知客户端每一个数据驻留在哪一个DataNode,客户端直接与DataNode进行通讯,DataNode还会与其它DataNode通讯,复制这些块以实现冗余。
NameNode和DataNode架构图
须要注意,SecondaryNameNode并非NameNode的备份。咱们从前面的介绍已经知道,全部HDFS文件的元信息都保存在NameNode的内存中。在NameNode启动时,它首先会加载fsimage到内存中,在系统运行期间,全部对NameNode的操做也都保存在了内存中,同时为了防止数据丢失,这些操做又会不断被持久化到本地edits文件中。
Edits文件存在的目的是为了提升系统的操做效率,NameNode在更新内存中的元信息以前都会先将操做写入edits文件。在NameNode重启的过程当中,edits会和fsimage合并到一块儿,可是合并的过程会影响到Hadoop重启的速度,SecondaryNameNode就是为了解决这个问题而诞生的。
SecondaryNameNode的角色就是按期的合并edits和fsimage文件,咱们来看一下合并的步骤:
最后再总结一下整个过程当中涉及到NameNode中的相关文件
HDFS经过备份数据块的形式来实现容错,除了文件的最后一个数据块外,其它全部数据块大小都是同样的。数据块的大小和备份因子都是能够配置的。NameNode负责各个数据块的备份,DataNode会经过心跳的方式按期的向NameNode发送本身节点上的Block 报告,这个报告中包含了DataNode节点上的全部数据块的列表。
文件副本的分布位置直接影响着HDFS的可靠性和性能。一个大型的HDFS文件系统通常都是须要跨不少机架的,不一样机架之间的数据传输须要通过网关,而且,同一个机架中机器之间的带宽要大于不一样机架机器之间的带宽。若是把全部的副本都放在不一样的机架中,这样既能够防止机架失败致使数据块不可用,又能够在读数据时利用到多个机架的带宽,而且也能够很容易的实现负载均衡。可是,若是是写数据,各个数据块须要同步到不一样的机架,会影响到写数据的效率。
而在Hadoop中,若是副本数量是3的状况下,Hadoop默认是这么存放的,把第一个副本放到机架的一个节点上,另外一个副本放到同一个机架的另外一个节点上,把最后一个节点放到不一样的机架上。这种策略减小了跨机架副本的个数提升了写的性能,也可以容许一个机架失败的状况,算是一个很好的权衡。
关于副本的选择,在读的过程当中,HDFS会选择最近的一个副本给请求者。
关于安全模式,当 Hadoop的NameNode节点启动时,会进入安全模式阶段。在此阶段,DataNode会向NameNode上传它们数据块的列表,让 NameNode获得块的位置信息,并对每一个文件对应的数据块副本进行统计。当最小副本条件知足时,即必定比例的数据块都达到最小副本数,系统就会退出安全模式,而这须要必定的延迟时间。当最小副本条件未达到要求时,就会对副本数不足的数据块安排DataNode进行复制,直至达到最小副本数。而在安全模式下,系统会处于只读状态,NameNode不会处理任何块的复制和删除命令。
全部的HDFS中的沟通协议都是基于tcp/ip协议,一个客户端经过指定的tcp端口与NameNode机器创建链接,并经过ClientProtocol协议与NameNode交互。而DataNode则经过DataNode Protocol协议与NameNode进行沟通。HDFS的RCP(远程过程调用)对ClientProtocol和DataNode Protocol作了封装。按照HDFS的设计,NameNode不会主动发起任何请求,只会被动接受来自客户端或DataNode的请求。
能够容许DataNode失败。DataNode会按期(默认3秒)的向NameNode发送心跳,若NameNode在指定时间间隔内没有收到心跳,它就认为此节点已经失败。此时,NameNode把失败节点的数据(从另外的副本节点获取)备份到另一个健康的节点。这保证了集群始终维持指定的副本数。
能够检测到数据块损坏。在读取数据块时,HDFS会对数据块和保存的校验和文件匹配,若是发现不匹配,NameNode一样会从新备份损坏的数据块。
了解客户端与NameNode和DataNode的交互过程十分重要,有助于加深咱们对hdfs架构设计的理解。
hdfs有一个FileSystem实例,客户端经过调用这个实例的open()方法就能够打开系统中但愿读取的文件。hdfs经过rpc调用NameNode获取文件块的位置信息,对于文件的每个块,NameNode会返回含有该块副本的DataNode的节点地址,另外,客户端还会根据网络拓扑来肯定它与每个DataNode的位置信息,从离它最近的那个DataNode获取数据块的副本,最理想的状况是数据块就存储在客户端所在的节点上。
hdfs会返回一个FSDataInputStream对象,FSDataInputStream类转而封装成DFSDataInputStream对象,这个对象管理着与DataNode和NameNode的I/O,具体过程是:
1. 客户端发起读请求 2. 客户端与NameNode获得文件的块及位置信息列表 3. 客户端直接和DataNode交互读取数据 4. 读取完成关闭链接
当FSDataInputStream与DataNode通讯时遇到错误,它会选取另外一个较近的DataNode,并为出故障的DataNode作标记以避免重复向其读取数据。FSDataInputStream还会对读取的数据块进行校验和确认,发现块损坏时也会从新读取并通知NameNode。
这样设计的巧妙之处:
在海量数据处理过程当中,主要限制因素是节点之间的带宽。衡量两个节点之间的带宽每每很难实现,在这里hadoop采起了一个简单的方法,它把网络拓扑当作是一棵树,连个节点的距离=它们到最近共同祖先距离的总和,而树的层次能够这么划分:
若数据中心d1中一个机架r1中一个节点n1表示为d1/r1/n1,则:
distance(d1/r1/n1,d1/r1/n1)=0; distance(d1/r1/n1,d1/r1/n2)=2; distance(d1/r1/n1,d1/r2/n3)=4; distance(d1/r1/n1,d2/r3/n4)=6;
hdfs有一个DistributedFileSystem实例,客户端经过调用这个实例的create()方法就能够建立文件。DistributedFileSystem会发送给NameNode一个RPC调用,在文件系统的命名空间建立一个新文件,在建立文件前NameNode会作一些检查,如文件是否存在,客户端是否有建立权限等,若检查经过,NameNode会为建立文件写一条记录到本地磁盘的EditLog,若不经过会向客户端抛出IOException。建立成功以后DistributedFileSystem会返回一个FSDataOutputStream对象,客户端由此开始写入数据。
同读文件过程同样,FSDataOutputStream类转而封装成DFSDataOutputStream对象,这个对象管理着与DataNode和NameNode的I/O,具体过程是:
1. 客户端在向NameNode请求以前先写入文件数据到本地文件系统的一个临时文件 2. 待临时文件达到块大小时开始向NameNode请求DataNode信息 3. NameNode在文件系统中建立文件并返回给客户端一个数据块及其对应DataNode的地址列表(列表中包含副本存放的地址) 4. 客户端经过上一步获得的信息把建立临时文件块flush到列表中的第一个DataNode 5. 当文件关闭,NameNode会提交此次文件建立,此时,文件在文件系统中可见
上面第四步描述的flush过程实际处理过程比较负杂,如今单独描述一下:
1. 首先,第一个DataNode是以数据包(数据包通常4KB)的形式从客户端接收数据的,DataNode在把数据包写入到本地磁盘的同时会向第二个DataNode(做为副本节点)传送数据。 2. 在第二个DataNode把接收到的数据包写入本地磁盘时会向第三个DataNode发送数据包 3. 第三个DataNode开始向本地磁盘写入数据包。此时,数据包以流水线的形式被写入和备份到全部DataNode节点 4. 传送管道中的每一个DataNode节点在收到数据后都会向前面那个DataNode发送一个ACK,最终,第一个DataNode会向客户端发回一个ACK 5. 当客户端收到数据块的确认以后,数据块被认为已经持久化到全部节点。而后,客户端会向NameNode发送一个确认 6. 若是管道中的任何一个DataNode失败,管道会被关闭。数据将会继续写到剩余的DataNode中。同时NameNode会被告知待备份状态,NameNode会继续备份数据到新的可用的节点 7. 数据块都会经过计算校验和来检测数据的完整性,校验和以隐藏文件的形式被单独存放在hdfs中,供读取时进行完整性校验
hdfs文件删除过程通常须要以下几步:
原文地址————https://yq.aliyun.com/articles/5905#1. 一开始删除文件,NameNode只是重命名被删除的文件到/trash目录,由于重命名操做只是元信息的变更,因此整个过程很是快。在/trash中文件会被保留必定间隔的时间(可配置,默认是6小时),在这期间,文件能够很容易的恢复,恢复只须要将文件从/trash移出便可。 2. 当指定的时间到达,NameNode将会把文件从命名空间中删除 3. 标记删除的文件块释放空间,HDFS文件系统显示空间增长