HDFS客户端读流程:
-
初始化FileSystem,然后客户端用DistributedFileSystem的open方法打开文件。
-
FileSystem用RPC调用元数据节点,采用getBlockLocations()得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。
-
FileSystem返回HdfsDataInputStream给客户端,用来读取数据,HdfsDataInputStream是DFSInputStream的装饰类,真正进行数据块读取的是DFSInputStream对象,客户端调用DFSInputStream的read()函数开始读取数据。
-
DFSInputStream连接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端。
-
当此数据块读取完毕时,HdfsDataInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。
-
当客户端读取完毕数据的时候,调用HdfsDataInputStream的close函数。
-
在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。
-
失败的数据节点会被记录,此后不再连接。
HDFS客户端写流程:
-
初始化FileSystem,然后客户端用DistributedFileSystem的open方法。
-
Client调用DistributedFileSystem对象的create方法,创建一个文件输出流(HdfsDataOutputStream)对象,此对象底层包装了DFSOutputStream对象,实际执行写数据的是DFSOutputStream对象。
-
HDFS客户端调用DFSOutputStream.write()方法来写数据。
-
DFSOutputStream通过RPC远程调用addBlock()方法,在HDFS的Namespace中创建一个文件条目(Entry),该条目没有任何的Block。
-
通过对象,向DataNode写入数据,数据首先被写入FSDataOutputStream对象内部的Buffer中,然后数据被分割成一个个Packet数据包。以Packet最小单位,基于Socket连接发送到按特定算法选择的HDFS集群中一组DataNode(正常是3个,可能大于等于1)中的一个节点上,在这组DataNode组成的Pipeline上依次传输Packet。
-
这组DataNode组成的Pipeline反方向上,发送ack,最终由Pipeline中第一个DataNode节点将Pipeline ack发送给Client。
-
当确认数据节点已经写入这个数据包,则从缓存队列删除。
-
完成向文件写入数据,Client在文件输出流(FSDataOutputStream)对象上调用close方法,关闭流。
-
调用DistributedFileSystem对象的complete方法,通知NameNode文件写入成功。