Hadoop简介:http://hadoop.apache.org
1. 组成
分布式文件存储系统HDFS (Hadoop Distributed File System )POSIX
分布式存储系统
提供了 高可靠性、高扩展性和高吞吐率的数据存储服务
分布式计算框架MapReduce
分布式计算框架(计算向数据移动)
具有 易于编程、高容错性和高扩展性等优点。
分布式资源管理框架YARN(Yet Another Resource Management)|2.0以后从MapRuduce中独立出来
负责集群资源的管理和调度
版本:1.x,2.x,3.x
2 .Hadoop的特性
.高可靠性
.高效性
.高可扩展性
.高容错性
.成本低
.运行Linux平台上,Windows也可以运行,但是并不建议
.支持多种编程语言
3.HDFS优点:
.高容错性
.数据自动保存多个副本
.副本丢失后,自动恢复
.适合批处理
.移动计算而非数据
.数据位置暴露给计算框架(Block偏移量)
.适合大数据处理
.GB 、TB 、甚至PB 级数据
.百万规模以上的文件数量
.10K+ 节点
.可构建在廉价机器上
.通过多副本提高可靠性
.提供了容错和恢复 机制
4.HDFS缺点:
.低延迟数据访问
.比如毫秒级
.低延迟与高吞吐率
.小文件存取
.占用NameNode 大量内存
.寻道时间超过读取时间
.并发写入、文件随机修改
.一个文件只能有一个写者
.仅支持append
HDFS (分布式文件系统)
架构模型:
文件元数据MetaData,文件数据
元数据
数据本身
(主)NameNode节点保存文件元数据:单节点 posix
(从)DataNode节点保存文件Block数据:多节点
DataNode与NameNode保持心跳,提交Block列表
HdfsClient与NameNode交互元数据信息
HdfsClient与DataNode交互文件Block数据(cs)
DataNode 利用服务器本地文件系统存储数据块
HDFS 1.0 架构图
**
NameNode 名称节点(NN**)
基于内存存储 :不会和磁盘发生交换(双向)
只存在内存中
持久化(单向)
NameNode主要功能:
接受客户端的读写服务,收集DataNode汇报的Block列表信息
NameNode保存metadata信息包括文件owership和permissions文件大小,时间(Block列表:Block偏移量),Block位置信息(持久化不存),Block每副本位置(由DataNode上报),NameNode并不会持久化存储这些信息,而是在系统每次启动时扫描所有的数据节点重构得到这些信息,并将其(FsImage和EditLog)合并。
FsImage(时点备份):fsimage就是在某一时刻,整个hdfs 的快照,它保存了最新的元数据检查点,包含了整个HDFS文件系统的所有目录和文件的信息。对于文件来说包括了数据块描述信息、修改时间、访问时间、各自的副本个数等;对于目录来说包括修改时间、访问权限控制信息(目录所属用户,所在组)等。
EditLog:主要是在NameNode已经启动情况下对HDFS进行的各种更新操作进行记录,HDFS客户端执行所有的写操作都会被记录到editlog中。
问题一
NameNode维护了文件与数据块的映射表以及数据块与数据节点的映射表,什么意思呢?
就是一个文件,它切分成了几个数据块,以及这些数据块分别存储在哪些datanode上,namenode一清二楚。
问题二
EditLog过大时,名称节点在启动过程中处于“安全模式”,只能对外提供读操作,无法提供写操作。当启动过程结束之后,系统将退出安全模式,对外提供正常的读写操作。但是,若EditLog很大会使得启动过程运行很慢,名称节点长期处于安全模式下,无法对外提供写操作。
解决方法:引入SecondaryNameNode(SNN)
注:HDFS的安全模式
SecondaryNameNode 第二名称节点(SNN)
它不是NN的备份(但可以做备份)
,
功能一:完成EditLog与FsImage的合并操作,减小EditLog的文件大小,以缩短名称节点启动时间。
每隔一段时间,SecondaryNameNode会与NameNode进行通信,请求NameNode停止使用EditLog文件,让NameNode将这之后新到达的写操作写入到一个新的文件EditLog.new中;然后SecondaryNameNode将EditLog、FsImage拉回至本地,加载到内存中——即将FsImage加载到内存中,再逐条执行EditLog中的记录,使FsImage保持最新。 以上,便是EditLog与FsImage的合并过程,合并完成之后,SecondaryNameNode将已经更新的FsImage文件发送到NameNode,NameNode收到后,就用这个最新的FsImage文件替换掉旧的FsImage,同时用EditLog.new文件去替换EditLog文件,这样一替换,同时也减小的EditLog文件的大小。
功能二:作为名称节点的检查点
从以下“合并过程”能看出,SecondaryNameNode会定期与NameNode通信,获取旧文件合并后得到一个FsImage的新文件。SecondaryNameNode周期性的备份NameNode中的元数据信息,当NameNode发生故障时,可用SecondaryNameNode中记录的元数据信息进行恢复。 但是,在合并、文件替换期间的更新操作并没有被写到新的FsImage文件中去,所以如果在这回期间发生故障,系统会丢失部分元数据信息。
DataNode 数据节点(DN)
本地磁盘目录存储数据(Block),文件形式,同时存储Block的元数据信息文件,启动DN时会向NN汇报block信息。通过向NN发送心跳保持与其联系(3秒一次),如果NN 10分钟没有收到DN的心跳,则认为其已经lost,并copy其上的block到其它DN
HDFS的读写过程
在介绍读写过程之前,先引入HDFS的存储原理
1.数据冗余存储
多副本方式的优点
1.加快数据传输的速度
2.容易检查数据错误
3.保证数据的可靠性
2.数据错误与恢复
3.数据存取策略
。。。。。。。。。。。。。在读写过程中介绍。
HDFS 读流程
1. 打开HDFS文件: HDFS客户端首先调用DistributedFileSystem.open方法打开HDFS文件,底层会调用ClientProtocal.open方法,返回一个用于读取的HdfsDataInputStream对象。
2.从NameNode获取DataNode地址:在构造DFSInputStream的时候,会调ClientPortocal.getBlockLocations方法向NameNode获取该文件起始位置数据块信息。NameNode返回的数据块的存储位置是按照与客户端距离远近排序的。所以DFSInputStream可以选择一个最优的DataNode节点,然后与这个节点建立数据连接读取数据块。
3.连接到DataNode读取数据块: HDFS客户端通过调用DFSInputSttream从最优的DataNode读取数据块,数据会以数据包packet形式从DataNode以流式接口传送到客户端,当达到一个数据块末尾的时候, DFSInputStream就会再次调用ClientProtocal.getBlockLoctions获取下一个数据块的位置信息,并建立和这个新的数据块的最优节点之间的连接,然后HDFS继续读取数据块。
4.客户端关闭输入流。
注意:客户端读取数据块的时候,很有可能这个数据块的DataNode出现异常,也就是无法读取数据。这时候DFSInputStream会切换到另一个保存了这个数据块副本的DataNode,然后读取数据。另外,数据块的应答不仅包含了数据块还包含了校验值,HDFS客户端收到数据应答包的时候,会对数据进行校验,md5算法校验数据完整性,SHA1算法校验数据真实性。如果校验错误,也就是DataNode这个数据块副本出现了损坏,HDFS 客户端会通过ClientProtocal.reportBadBlocks向NameNode汇报这个损坏的数据块副本,同时DFSInputStream会尝试从其他DataNode读取这个数据块
DataNode读文件过程
HDFS客户端发送Sender.readBlock之后,DataXceiverServer检测到有新的请求到来,监听是否有请求进来;如果有新的请求进来,则构造一个流式接口DataTransferProtocol的子类Receiver子类:DataXceiver线程服务这个请求,并启动这个DataXceiver。 DataXceiver启动之后会解析请求操作,并根据请求操作码调用具体的方法opReadBlock。
HDFS 写流程
Client(客户端):
切分文件Block
按Block线性和NN获取DN列表(副本数)
验证DN列表后以更小的单位流式传输数据
各节点,两两通信确定可用
Block传输结束后:
DN向NN汇报Block信息
DN向Client汇报完成
Client向NN汇报完成
获取下一个Block存放的DN列表
。。。。。。
最终Client汇报完成
NN会在写流程更新文件状态
HDFS写流程(详述)
1.HDFS 客户端调用DistributedFileSystem.create()方法
2.DistributedFileSystem调用ClientProtocal,create()方法通过RPC协议在NameNode的文件系统目录树中创建一个文件,并且创建新文件的操作记录到editlog中,返回一个HdfsDataOutputStream对象,底层是对DFSOutputStream进行了一个包装。在创建文件之前,NameNode会做一些检查,比如文件是否已经存在,客户端是否有权限创建文件等。
3.HDFS 客户端根据返回的输出流对象调用write方法来写数据
4. DFSOutputStream首先会将需要写入的数据分成一个个的分包,这些分包被放入DFSOutputStream 对象的内部队列。由于之间创建的新文件是一个空文件,并没有申请任何数据块,所以会调用ClientProtocal.addBlock向NameNode申请数据块,数据块的大小可以由用户自己配置,默认128M(以前是64M),NameNode返回一个LocatedBlock对象,这个对象保存了这个数据块所有DataNode位置信息,然后就可以建立数据流管道写数据块了。
5.建立通向DataNode的数据流管道,写入数据:建立数据流管道之后,HDFS客户端就可以向数据流管道写数据。它会将数据切分成一个个的数据包packet,然后通过数据流管道发送到DataNode
6.每一个packet都有一个确认包(ACK Packet),逆序的通过数据流管道回到输出流。输出流在确认了所有的DataNode(数据复制)已经写入了这个数据包,就会从对应的缓存队列删除这个数据包,直到数据全部写完。
7.当DNode成功接收一个数据块时,DataNode会通过DataNodeProtocal.blockReceivedAndDelete方法向NameNode汇报,NameNode会更新内存中数据块和数据节点的对应关系。
8.当数据全部写完,并且全部写完确认以后,客户端会调用close()方法关闭输出流,此时开始,客户端不会再向输出流中写入数据。
DataNode写文件的流程
HDFS客户端通过流式接口DataTransferProtocol的子类Sender调用writeBlock,向数据流管道写入数据。在写的时候会传入从NameNode查询到的可用DataNode的信息。 DataNode在启动的时候,会创建DataXceiverServer对象,并以后台方式运行,DataXceiverServer是一个线程类,它会一直判断DataNode是否运行正常,监听是否有请求进来;如果有新的请求进来,则构造一个流式接口DataTransferProtocol的子类Receiver子类:DataXceiver线程服务这个请求,并启动这个DataXceiver。
DataXceiver启动之后,会解析当前输入流中的操作,是读还是写等,我们这里是写操作,那么操作码就是:WRITE_BLOCK,然后根据解析的WRITE_BLOCK作为参数,针对不同的操作码调用Receiver不同的方法,比如这里就是opWriteBlock方法.
客户端会将数据块切分成不同的数据包packet,数据包首先发送到第一个DataNode节点,成功接收后,会将数据包写入磁盘,然后将数据包发送到数据流管道中的第二个DataNode节点,以此类推,到数据流管道最后一个也就是第三个DataNode,会对收到的数据包进行校验,校验成功,DataNode3会发送数据包确认消息,这个消息会逆向的通过数据流管道回到客户端。当一个数据块中所有数据包发送完毕,并且受到确认消息,客户端会发送一个空的数据包标识当前数据块已经发送完毕。
补充:数据复制(流水线式的复制)
当某个客户端向HDFS文件写数据的时候,一开始是写入本地的临时文件,假设该文件的replication因子为3,那么客户端会从NameNode获取一张DataNode列表来存放副本。然后客户端开始向第一个DataNode传输数据,第一个DataNode会一小部分一小部分(4KB)地接收数据,将每个部分写入本地仓库,同时传输该部分到第二个DataNode。第二个DataNode也是这样,边收边传,一小部分一小部分地接收,将每个部分存储在本地仓库,同时传给第三个DataNode。第三个DataNode仅仅接收并存储。这就是流水线式的复制。
补充:写流程中备份(数据复制)时,其中一个写失败了怎么办?
① Pipeline数据流管道会被关闭,ACK queue中的packets会被添加到data queue的前面以确保不会发生packets数据包的丢失
② 在正常的DataNode节点上的以保存好的block的ID版本会升级——这样发生故障的DataNode节点上的block数据会在节点恢复正常后被删除,失效节点也会被从Pipeline中删除
③ 剩下的数据会被写入到Pipeline数据流管道中的其他两个节点中*
HDFS文件权限 POSIX标准(可移植操作系统接口)
与Linux文件权限类似
r: read; w:write; x:execute
权限x对于文件忽略,对于文件夹表示是否允许访问其内容
如果Linux系统用户zhangsan使用hadoop命令创建一个文件,那么这个文件在HDFS中owner就是zhangsan。
HDFS的权限目的:阻止误操作,但不绝对。HDFS相信,你告诉我你是谁,我就认为你是谁。