Hadoop学习——hdfs上传读取删除文件的过程
- namnode,名字节点,最主要管理HDFS的元数据信息。
- datanode,数据节点,存储文件块
- replication,文件块的副本,目的是确保数据存储的可靠性
- rack 机器
- Client 客户端。凡是通过指令或代码操作的一端都是客户端
- Client 的Read(从HDFS下载文件到本地)
- Client的Write(上传文件到HDFS上)
从HDFS上读取文件的过程
-
客户端发起
open File
,目的是获取要下载的文件的输入流。
namenode
收到请求之后,会检查路径的合法性,以及客户端的权限。 -
客户端在发起
open file
的同时,还会调用getblockLocation
。当第一步监测都通过之后,namenode
会将元数据信息全部或者部分封装到输入流
中,返回给客户端。 -
客户端用
输入流
,根据元数据信息,去指定的datanode
读取文件块,一般去最近的节点上获取数据。(按照blockid
的顺序读取)。之所以不是namenode
来拿数据返回给datanode
,而是客户端自己去找,是因为namenode
仅有一个,会有单点问题,减少了namenode
的压力。 -
同上。如果没有读完,则仍旧请求
namenode
,去要下一个块的信息。 -
文件下载完成后关闭连接。
-
读取每个块的过程中会有校验的过程,校验不一致,则通知
namenode
。重新读取。
1、校验是在发送数据前将数据通过MD5算出一个唯一标识码,
并将该标识码随数据包一起发送给客户端。
2、客户端收到数据后也以同样方式算出一个标识码,两者进行比较,
如果不同,则表示文件传输缺失。
HDFS上传文件的过程
- 客户端发起
create file
请求,目的是获取hdfs
文件的输出流。namenode
收到请求后会检测路径的合法性,以及权限。原生Hadoop
权限管理不是很完善,工作中用的是cdh
(商业版hadoop
)。 - 如果检测都通过,
namenode
会为这个文件生成块的元数据信息(比如文件切块
、分配块id
、分配每个块存在哪个datanode
上),然后将该信息返回给客户端。 - 客户端拿出输出流之后,采用
pipeline
(数据流管道)机制做数据的发送。副本一般都是3个,但是为什么在拷贝中是一个datanode
,然后在datanode
之间线性传输,而不是一次给三个datanode
那样拓扑式传输呢?这样的数据以管道的方式,顺序的沿着一个datanode
传输,这样能够充分利用每个机器的带宽,避免网络瓶颈和高延迟时的连接,最小化推送所有数据的延时。在线性推送模式下,每台机器所有的出口宽带都用于以最快的速度传输数据,而不是在多个接受者之间分配宽带。
packet
是一个64kb
大小的数据包,即客户端在发送文件块时,会把文件打散成一个个的数据包,发送给datanode
。
4.5 每台datanode
收到packet
后,会向上游datanode
做ack
确认,如果接受失败,会进行重发。
6.当一个文件上传完后,关流。
HDFS删除文件的过程
- 当客户端发起一个删除指令
hadoop fs -rm /park01/1.txt
,这个指令会传给namenode
。 - 当
namenode
收到指令后,做路径和权限检测,如果检测都通过,会将对应的文件信息从内存中删除。此时,文件数据并不是马上就从集群上被删除。 datanode
向namenode
发送心跳时,会领取删除指令,然后从磁盘上将文件删除。
hdfs读取文件的源码分析
DFSClicent
类,利用ClientProtocol
这个接口,通过rpc
的形式与namenode
进行通信。ClientProtocol
里,会调用namenode
的方法。
DFSInputStream
是在DFSClicent
通过ClientProtocol
接口,利用rpc
在向namenode
发起open file
命令是,namenode
会返回客户端一个DFSInputStream
流,该流里封装着元数据信息(即LocatedBlocks
l类)以及DatanodeInfo
节点信息。客户端再通过流中的BlockReader
去datanode
读取数据。
hdfs上传文件的源码分析
客户端在文件上传的时候发起write
请求,namenode
返回一个DFSOutputStream
输出流。输出流会将文件打散成64kb
的包(Packet
),并且每个包含有一个512b
的校验码(DataChecksum
),然后创建一个数据队列dataqueue
,将所有数据包加到·dataqueue
队列中,最后启动DataStreamer
线程。
上边说过:
在打散包时,会对每个包算出一个校验码,在发送过程中也将校验码发送到
datanode,datanode在接受后,也会以相同逻辑算一次校验码,
通过自己算出来的和传过来的校验码两者是否一致,来确定数据的完整性。
DataStreamer
(后台线程继承了Daemon
)线程通过数据管道,将包发送给第一个datanode
,并且将数据再放一份到一个新的队列中ackqueue
。ackqueue
的作用在发送失败的时候,可以从该队列里恢复,确保数据的完整。
ResponseProcessor
线程就是专门来收集拷贝后的ack
如果失败了之后,它会执行从ackqueue
里取数据重新发送,如果发送成功了。则删除ackqueue
的数据。
注意:
ackqueue和dataque都是LinkedList<Packet>类型,Packet即是上边的数据块,
LinkedList的特点是无界,并且增删快的特点。
datanode源码
DataNode
是一个类。
DataNodeProtocol
接口是namenode
和datanode
之间交互的接口,比如sendHeartbeat
心跳方法。
BlockerSender
是从datanode
的角度来看,它作为发送给客户端数据、datanode
之间传输数据的接口。
另外,在集群中当数据分布不均匀时,开启负载均衡工具时,也会用到BlockerSender
。即hadoop
安装目录下sbin
目录中的start-balancer.sh
,在执行如下命令时:
start-balancer.sh -t 10% //10%表示各节点之间数据的偏差率不能高于10%
注意该命令不是永久的,如果再填入新节点,也需要执行一下,才会有效。
ClientDatanodeProtocol
即客户端和datanode
交互的接口。