HDFS读写流程梳理

HDFS读写流程

hdfs的读写主要设计Client、NameNode、DataNode等节点

HDHS客户端进行文件读操作流程

HDFS读写流程梳理
1.打开HDFS文件,构造DFSInputStream输入流
HDFS客户端调用DistributesFileSystem.open()方法打开HDFS文件,其底层实际上是调用ClientPropocol.open()方法,返回一个HdfsDataInputStream(DFSInputStream的装饰类,真正进行读取操作是DFSInputStream)。
2.从NameNode端获取数据存储的DataNode地址
DFSInputStream的构造方法中,会调用ClientProtocol.getBlockLocations()方法获取该JDFS文件起始位置数据块的位置信息。NameNode会按照储存位置与客户端的距离排序选择最优的一个DataNode节点。
3.建立数据连接(流式接口)
DFSInputStream.read()方法从数据节点读取数据,数据会以数据包(packet)为单位从数据节点传送到客户端。当一个数据块读取结束,则DFSInputStream会重新调用ClientProtocol.getBlockLocations()获取文件的下一个数据块位置,并与其最优节点建立连接,重复以上动作。
4.关闭输入流
当客户端完成文件读取后,通过HdfsDataInputStream.close()方法关闭输入流。
另外数据块的应答包中除了包含数据还包含校验码,HDFS收到数据后会进行校验,如果发生错误,则会通过ClientProtocol.reportBadBlocks()向名字节点汇报损坏的数据块的信息,并且DFSInputStream会切换到另外一个保存该数据块的节点读取文件。

HDFS客户端进行文件写操作流程

HDFS读写流程梳理
1.创建文件
client发起文件上传请求,调用DistributedFileSystem对象的create方法,在HDFS系统中创建一个新的空文件,该方法在底层调用ClientProtocol.creat()方法通过RPC与NameNode建立连接,NameNode检查目标文件是否已经存在,父目录是否存在,并检查用户是否有相应的权限,若检查通过,Namenode会在文件系统目录树下的指定目录下创建一个新文件文件,但未申请任何Block,并将该操作记录在editlog中,否则的话文件创建失败,客户端得到异常信息
2.获取HdfsDataOutputStream对象
ClientProtocol.creat()调用结束后,DistributedFileSystem.create()方法会返回一个HdfsDataOutputStream(DFSOutputStream的包装类,真正起作用的是DFSOutputStream)
3.获取Block信息及信息流管道
这时,名字节点只是在目录上创建一个空文件,DFSOutputStream会调用ClientProtocol.addBlock()向NameNode获取资源,NameNode根据配置文件中指定的备份(replica)数量及机架感知原理进行文件分配,返回LocatedBlock对象,其记录了保存该数据块的节点的信息,就DFSOutputStream会建立数据管道写数据块了。以三台DataNode为例:A B C。注: Hadoop在设计时考虑到数据的安全与高效,数据文件默认在HDFS上存放三份,存储策略为:第一个备份放在客户端相同的datanode上(若客户端在集群外运行,就随机选取一个datanode来存放第一个replica),第二个replica放在与第一个replica不同机架的一个随机datanode上,第三个replica放在与第二个replica相同机架的随机datanode上,如果replica数大于三,则随后的replica在集群中随机存放,Hadoop会尽量避免过多的replica存放在同一个机架上.选取replica存放在同一个机架上.(Hadoop 1.x以后允许replica是可插拔的,意思是说可以定制自己需要的replica分配策略)
4.成功建立数据管道后,HDFS客户端可以开始写数据,写入DFSOutputStream的数据会被缓存在数据流中,以数据包(packet)的形式存在,写满一个packet对象则将其放在输出队列中(dataQueue)中,等待DataStream线程处理。
5.DataStream线程处理dataQueue中的数据
首先会进行错误处理(处理方式主要为三步:关闭当前IO流、将ackQueue中等待确认的数据包全部移到dataQueue中、重新初始化数据流管道进行写入),之后等待dataQueue写满,然后在第一个datanode上建立数据流管道,发送数据包。当写完当前Block后会重新申请Block.例如:client向请求的3台的DataNode中的A上传数据,(本质是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将整个pipeline建立完成后,逐级返回client。client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位(默认 64K),A收到一个packet就会传给B,B传递给C;A每传一个packet会放入一个应答队列等待应答,如果数据包都得到确认则删除应答队列中的数据包。
6.关闭输入流并提交文件
当所有数据上传完成后,可以调用close()方法关闭输入流,并调用Clientprotocol.complete()告诉NameNode文件写入完成。
有可能管道线中的多个datanode宕掉(一般这种情况很少),但只要dfs.relication.min(默认值为1)个replica被创建,我么就认为该创建成功了,剩余的relica会在以后异步创建以达到指定的replica数。当一个block传输完成后,client再次发送请求NameNode上传第二个block到服务器
HDFS读写流程梳理

参考文章:https://blog.****.net/dpengwang/article/details/79297435
https://www.cnblogs.com/zengfa/p/9323346.html