HDFS学习笔记

hadoop

    • 架构
      • NameNode
      • DataNode
      • SecondaryNameNode
    • 文件读取流程
    • 文件写入流程
    • HA

架构

NameNode

DataNode

SecondaryNameNode

文件读取流程

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path file = new Path("demo.txt"); 
FSDataInputStream inStream = fs.open(file);
String data = inStream.readUTF();
System.out.println(data);
inStream.close();

读取流程图1:
HDFS学习笔记_第1张图片

1.客户端调用FileSystem(DistributedFileSystem的一个实例)的open()
2.DistributedFileSystem向namenode发起rpc请求,以确定文件中前几块的位置

对于每个块,namenode返回具有该块副本的datanode的地址。此外,datanode根据它们与客户端的距离(根据集群网络的拓扑结构)进行排序。如果客户端本身是datanode(例如,在MapReduce任务中),那么如果datanode含有该块的副本,客户端将从本地datanode读取数据。
DistributedFileSystem将一个FSDataInputStream(支持file seek的输入流)返回给客户端,以便客户端从中读取数据。FSDataInputStream封装了DFSInputStream,它用来管理datanode和namenode I/O。

3.客户端调用FSDataInputStreamread()
4.DFSInputStream存储了文件中前几个块的datanode地址,然后连接到文件中第一个块的第一个(最近的)datanode。客户端在流上重复调用read(),数据从datanode流回客户端
5.当读完第一个block后,DFSInputStream会关闭与datanode的连接,然后为下一个block找到最佳的datanode

对于客户端来说是透明的,从客户端的角度看,这只是读取一个连续的数据流。块是按顺序读取的,当客户端读取流时,DFSInputStream打开到datanode的新连接。它还将调用namenode,根据需要检索下一批块的datanode位置。

6.客户端完成读取时,调用FSDataInputStreamclose()

在读取期间,如果DFSInputStream在与datanode通信时遇到错误,它将尝试该块的下一个最近的datanode。它还将记住失败的datanode,这样它就不必在以后的块中重试它们了。DFSInputStream还验证从datanode传输到它的数据的校验和。如果发现损坏的块,DFSInputStream尝试从另一个datanode读取块的副本;它还将损坏的块报告给namenode。
这种设计的一个重要方面是,客户端直接联系datanode来检索数据,并由namenode引导到每个块的最佳datanode。这种设计允许HDFS扩展到大量并发客户端,因为数据流量分布在集群中的所有datanode上。与此同时,namenode只需要服务于块位置请求(它将这些请求存储在内存中,这使得它们非常有效),而不需要服务于数据,这将随着客户端数量的增长而迅速成为瓶颈。

文件写入流程

Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path file = new Path("demo.txt");
FSDataOutputStream outStream = fs.create(file);
outStream.writeUTF("HELLO HDFS!");
outStream.close();

写入流程图2:
HDFS学习笔记_第2张图片
1.客户端通过FileSystem发起create请求
2.DistributedFileSystem向namenode发起rpc请求,以在文件系统的名称空间中创建一个新文件(没有与之关联的块)

namenode执行各种检查,以确保文件不存在,并且客户端具有创建文件的正确权限。如果这些检查通过,namenode将记录新文件;否则,文件创建失败,客户端将抛出IOException。
DistributedFileSystem返回一个FSDataOutputStream,供客户端向其写入数据。FSDataOutputStream封装了DFSOutputStream,它处理与datanode和namenode的通信。

3.当客户端写入数据时,DFSOutputStream将数据拆分成packets,并将packet写入data queue。data queue由DataStreamer使用,它负责通过选择合适的datanode列表来存储副本,从而要求namenode分配新块。datanode列表形成一个pipeline,这里我们假设副本数为3,所以pipeline中有3个datanode
4.DataStreamer将packet写到pipeline中的第一个datanode,后者存储每个数据包并将其转发到pipeline中的第二个datanode。类似地,第二个datanode存储数据包并将其转发到pipeline中的第三个datanode
5.DFSOutputStream还维护一个等待datanode确认的packet的内部队列ack queue。只有当一个数据包被pipeline中的所有datanode确认后,它才会从ack queue中删除

如果任何datanode在写入数据时失败,那么将执行以下操作,这些操作对于写入数据的客户端是透明的。首先,关闭pipeline,将ack队列中的任何数据包添加到data queue的前端,这样来自失败节点的下游datanode将不会错过任何数据包。良好datanode上的当前块被赋予一个新标识,该标识被传递给namenode,这样,如果失败的datanode稍后恢复,失败的datanode上的部分块将被删除。将失效的datanode从pipeline中移除,用两个好的datanode构建一条新的pipeline。块的其余数据被写入pipeline中的良好datanode。namenode注意到块的复制不足,并安排在另一个节点上创建进一步的复制。随后的块将被视为正常。
在编写一个块时,多个datanode可能会失败,但不太可能。只要写入了dfs.namenode.replication.min副本(默认值为1),写入就会成功,并且块将在集群中异步复制,直到达到目标复制因子为止(dfs)。复本数默认为3)。

6.当客户端写完数据后,它会调用FSDataOutputStreamclose(),这个动作会将所有剩余的数据包刷新到datanode pipeline,并等待确认
7.向namenode报告数据写入完成

HA

高可用架构图3
HDFS学习笔记_第3张图片


  1. http://www.corejavaguru.com/bigdata/hadoop/hdfs-file-read ↩︎

  2. http://www.corejavaguru.com/bigdata/hadoop/hdfs-file-write ↩︎

  3. https://issues.apache.org/jira/browse/HDFS-1623 ↩︎

你可能感兴趣的:(hadoop)