一、
HDFS
总体结构示意图
1. 图中展现了整个HDFS三个重要角色:NameNode、DataNode和Client
1) NameNode可以看作是分布式文件系统中的管理者,主要负责管理文件系统的命名空间、集群配置信息和存储块的复制等。NameNode会将文件系统的Meta-data存储在内存中,这些信息主要包括了文件信息、每一个文件对应的文件块的信息和每一个文件块在DataNode的信息等。
2) DataNode是文件存储的基本单元,它将Block存储在本地文件系统中,保存了Block的Meta-data,同时周期性地将所有存在的Block信息发送给NameNode。
3) Client就是需要获取分布式文件系统文件的应用程序。
2.
文件写入
1) Client向NameNode发起文件写入的请求。
2) NameNode根据文件大小和文件块配置情况,返回给Client它所管理部分DataNode的信息。
3) Client将文件划分为多个Block,根据DataNode的地址信息,按顺序写入到每一个DataNode块中。
3.
文件读取
1) Client向NameNode发起文件读取的请求。
2) NameNode返回文件存储的DataNode的信息。
3) Client读取文件信息。
二 、 文件读取剖析
为了了解Hadoop客户端及与之交互的HDFS、名称节点(Namenode)和数据节点(Datanode)之间的数据流的情况,可通过下图进行了解,图中显示了再读取文件时事件的主要顺序。
流程图说明:
1. 客户端通过调用FileSystem对象的open()来读取希望打开的文件,对于HDFS来说,这个对象是分布式文件系统的一个实例。
2. 分布式文件系统(Distributed Filesystem)通过使用RPC来调用名称节点,以确定文件开头部分的块的位置;
1) 对于每一个块,名称节点返回具有该块副本的数据节点的地址;
2) 此外,这些数据节点根据他们与客户端的距离来排序(在同一机架上同一个节点距离为0;同一机架上不同节点距离为2;同一数据中心不同机架的节点距离为4)
3) 如果该客户端本身就是一个数据节点,便从本地数据节点读取。
3. 分布式文件系统(Distributed Filesystem)返回一个FSData InputStream对象(一个支持文件定位的输入流)给客户端读取数据,FSdata InputStream转而封装了一个DFSInputStream对象。接着,客户端对这个输入流调用read()。
4. DFS InputStream存储着文件开头部分的块的数据节点地址,DFS InputStream与这些块最近的数据节点相连接,通过在数据流中重复调用read(),数据会从Datanode返回客户端。
5. 到达块的末端时,DFS InputStream会关闭与数据节点间的联系,然后为下一个块找到最佳的数据节点。
6. 客户端是从流中读取数据,块是按照DFS InputStream打开与数据节点的新连接的顺序读取的。
1) 它也会调用名称节点来检索下一组所需要块的数据节点地址,一但客户端完成读取,就对文件系统数据输入流调用close()。
2) 在读取的时候,如果客户端在与数据节点通信时遇到错误,它会尝试与下一个最近的块通信。
综上:
Ø 这个读取流程的重点是,客户端直接联系数据节点去检索数据,并通过名称节点的指引,到每个块中最好的数据节点。
Ø 因为数据在集群中的流动时在所有数据节点分散进行的,所以这种设计能使HDFS可扩展到最大的并发客户端数量。
Ø 名称节点只是提供位置请求(存储在内存中,因而非常高效),不是提供数据。
一、
文件写入剖析
从下图中可了解文件是如何写入HDFS的。我们考虑的情况是创建一个新的文件,向其写入数据后关闭该文件。
流程图说明
1. 客户端通过在分布式文件系统(DistributedFilesystem)中调用create()来创建文件。
2. 分布式文件系统(Distributed Filesystem)通过使用RPC来调用名称节点,在文件系统的命名空间中创建一个新的文件,没有块与之相联系。
1) 名称节点执行各种不同的检查以确保这个文件不会已经存在,并且客户端有可以创建文件的适当的许可。
2) 如果这些检查通过,名称节点就会生产一个新文件的记录;否则,文件创建失败并向客户端抛出一个IOException异常。
3. 分布式文件系统返回一个文件系统数据输出流(FSDataOutputStream),让客户端开始写入数据。
1) 就像读取数据一样,文件系统数据输出流(FSDataOutputStream)控制一个DFSOutputStream,负责处理数据节点(datanode)和名称节点(namenode)之间的通信。
2) 在客户端写入数据时,FSDataOutputStream将数据分成一个个包,写入内部队列,称为数据队列。数据队列随数据流流动,数据流的责任是根据适合的数据节点的列表来要求这些节点为副本分配新的块。
3) 数据节点的列表形成一个管线。
4. 数据流将包分流给管线中第一个数据节点,这个节点会存储包并且发送给管线中的第二个数据节点。同理,第二个数据节点存储包并且传给管线中第三个数据节点。
5. DFSOutputStream也有一个内部的包队列来等待数据节点收到确认,称为确认队列;一个包只有在被管线中所有节点确认后才会被移出确认队列。
6. 客户端完成数据写入后,就会在流中调用close()
7. 在向名称节点发送完信息之前,此方法会将余下的所有包放入数据节点管线并等待确认。