1.目的

HDFS遵循Write一次读取多次模型。所以我们不能编辑已经存储在HDFS中的文件,但我们可以通过重新打开文件来附加数据。在读写操作客户端中,首先与NameNode进行交互。 NameNode提供权限,客户端可以轻松地将数据块读入/写入相应的datanode。在这章中,我们将讨论Hadoop HDFS数据读写操作的内部结构。我们还将介绍客户端如何从HDFS读取和写入数据,以及客户端如何在HDFS数据读取和写入操作中与主节点和从节点进行交互。

2. Hadoop HDFS数据读写操作

HDFS – Hadoop分布式文件系统是Hadoop的存储层,是最可靠的存储系统。 HDFS以主从方式工作,NameNode是在主节点上运行的主守护进程,DataNode是在从节点上运行的从守护进程。

在开始使用HDFS之前,您应该安装Hadoop。可以选择:–

在单个节点上安装Hadoop

在多节点群集上安装Hadoop

在这里,我们将介绍HDFS数据的读写操作。先讨论HDFS文件写入操作,然后再讨论HDFS文件读取操作 –

2.1 Hadoop HDFS数据写入操作

要在HDFS中写入文件,客户端需要与主节点即namenode(主节点)进行交互。现在,namenode提供客户端将开始写入数据的datanode(从属)的地址。客户端直接在datanode上写入数据,datanode会创建数据写入管道。

第一个datanode会将该块复制到另一个datanode,该实例会将其复制到第三个datanode。一旦它创建块的副本,它就会发回确认。

HDFS数据写入管道工作流程

现在我们来了解完整的端到端HDFS数据写入管道。HDFS中的数据写入操作是分布式的,客户端将数据分散地复制到datanodes上,数据写入操作的步骤说明是:

i)HDFS客户端在DistributedFileSystem API上发送创建请求。

ii)DistributedFileSystem对名称节点进行RPC调用,以在文件系统的名称空间中创建一个新文件。 namenode执行各种检查以确保文件不存在,并且客户端有权创建文件。当这些检查通过时,只有namenode记录新文件;否则,文件创建失败,客户端抛出IOException。

iii)DistributedFileSystem为客户端返回一个FSDataOutputStream以开始写入数据。当客户端写入数据时,DFSOutputStream将其拆分成数据包,写入一个称为数据队列的内部队列。数据队列由DataStreamer使用,负责通过选择合适的datanode列表来存储副本,从而要求namenode分配新块。

iv)数据节点列表形成一个管道,在这里我们假设复制级别为3,所以管道中有三个节点。 DataStreamer将数据包流式传输到管道中的第一个数据节点,后者存储数据包并将其转发到管道中的第二个数据节点。类似地,第二个datanode存储数据包并将其转发到流水线中的第三个(也是最后一个)数据节点。

v)DFSOutputStream还维护一个等待被datanode确认的内部队列,称为ack队列。 仅当数据包已被流水线中的datanodes确认后才会从ack队列中删除数据包。 一旦创建需要的副本,Datanode发送确认(默认为3)。 同样,所有块都存储并复制到不同的datanode上,并行复制数据块。

vi)当客户端写完数据时,它在流上调用close()。

vii)此操作会将所有剩余数据包刷新到datanode管道,并在联系namenode之前等待确认,表示文件已完成。 namenode已经知道文件由哪些块组成,因此只需等待块成功返回之前就被最小程度地复制。

2.1 HDSF 数据写操作

如何在HDFS中编写文件 – Java程序

用Java将文件写入HDFS的示例代码如下所示:

FileSystem fileSystem = FileSystem.get(conf);
// Check if the file already exists
Path path = newPath(“/path/to/file.ext”);
if(fileSystem.exists(path)) {
System.out.println(“File ” + dest + ” already exists”);
return;
}
// Create a new file and write data to it.
FSDataOutputStream out = fileSystem.create(path);
InputStream in = newBufferedInputStream(new FileInputStream(
newFile(source)));
byte[] b = newbyte[1024];
int numBytes = 0;
while((numBytes = in.read(b)) > 0) {
out.write(b, 0, numBytes);
}
// Close all the file descripters
in.close();
out.close();
fileSystem.close();

2.2  Hadoop HDFS数据读取操作

要从HDFS读取文件,客户端需要与namenode(主)进行交互,因为namenode是Hadoop集群的核心(它存储所有元数据,即有关数据的数据)。 现在,namenode检查所需的权限,如果客户端具有足够的权限,则namenode将提供存储文件的从站的地址。 现在客户端将直接与相应的datanodes进行交互以读取数据块。

HDFS文件读取工作流程

现在我们来了解完整的端到端HDFS数据读取操作。 HDFS中的数据读取操作是分布式的,客户端从datanodes中并行读取数据,数据读取周期的步骤是:

i)客户端通过在FileSystem对象上调用open()来打开它希望读取的文件,该对象对于HDFS是DistributedFileSystem的一个实例。

ii)DistributedFileSystem使用RPC调用namenode来确定文件中头几个块的块位置。对于每个块,namenode返回具有该块的副本的datanode的地址,并且datanode根据它们与客户端的邻近性进行排序。

iii)DistributedFileSystem将FSDataInputStream返回给客户端,以便从中读取数据。因此,FSDataInputStream封装了管理datanode和namenode I / O的DFSInputStream。客户端调用流上的read()。已存储数据节点地址的DFSInputStream然后连接到文件中第一个块的最近数据节点。

iv)数据从数据节点流式传输回客户端,因此客户端可以在流上重复调用read()。块结束时,DFSInputStream将关闭与datanode的连接,然后找到下一个块的最佳数据节点。

v)如果DFSInputStream在与数据节点通信时遇到错误,它将尝试该块的下一个最接近的一个。它还会记住已失败的datanode,以便它不会不必要地重试它们以用于以后的块。 DFSInputStream还验证从数据节点传输给它的数据的校验和。如果发现损坏的块,它会在DFSInputStream尝试从另一个数据节点读取该块的副本之前将其报告给namenode。

vi)当客户端读完数据时,它在流上调用close()。

我们可以从下图中总结HDFS数据读取操作:

如何从HDFS读取文件 – Java程序

从HDFS读取文件的示例代码如下

FileSystem fileSystem = FileSystem.get(conf);
Path path = newPath(“/path/to/file.ext”);
if(!fileSystem.exists(path)) {
System.out.println(“File does not exists”);
return;
}
FSDataInputStream in = fileSystem.open(path);
int numBytes = 0;
while((numBytes = in.read(b))> 0) {
System.out.prinln((char)numBytes));// code to manipulate the data which is read
}
in.close();
out.close();
fileSystem.close();

3. HDFS中的容错

正如我们已经详细讨论过HDFS数据读写操作一样,现在,当其中一台机器(即运行datanode进程的管道的一部分)失败时会发生什么情况。 Hadoop具有内置的功能来处理这种情况(HDFS是容错的)。当数据正在写入数据时发生故障时,会采取以下操作,这些操作对写入数据的客户端来说是透明的。

首先,关闭管道,并将ack队列中的所有数据包添加到数据队列的前端,以便故障节点下游的datanode不会错过任何数据包。

良好数据节点上的当前块被赋予一个新的身份,该身份会传递给名称节点,以便稍后恢复失败的数据节点时恢复失败的数据节点上的部分块。

将失败的datanode从流水线中移除,然后将该块的其余数据写入流水线中的两个良好数据节点。

namenode注意到该块被复制不足,并且它安排在另一个节点上创建另一个副本。然后它将后续块视为正常。

在客户端写入数据块时,有可能(但不太可能)多个datanode发生故障。只要它写入dfs.replication.min副本(默认为1),写入将会成功,并且该块将跨群集异步复制,直到达到目标复制因子(dfs.replication,默认值为3)。

故障转移过程与数据写入操作相同,数据读取操作也是容错的。

Hadoop HDFS中的NameNode高可用性

4 结论

总之,这种设计允许HDFS增加客户数量。这是因为数据流量在集群的所有Datanode上都会传播。它还提供高可用性,机架感知,缩减编码等功能。



关注微信服务号,手机看文章
关注微信服务号,手机看文章