HDFS 教程: Archi结构,阅读和写作 OperaTION

⚡ 智能摘要

HDFS 是 Hadoop 的分布式存储层,它将超大文件分割成多个数据块,并分布在普通机器上,从而实现单个 NameNode 的高效运行。 tracks 元数据,同时许多数据节点可靠地处理读取和写入请求。

  • 🔘 结 构: NameNode 保存命名空间镜像和编辑日志,而 DataNode 存储实际的块副本。
  • ☑️ 块尺寸: Hadoop 1.x 默认使用 64 MB 的数据块;Hadoop 2.x 和 3.x 则默认使用 128 MB 的数据块。
  • ✅ 复制: 每个数据块默认有三个副本,分布在多个机架上,因此硬件故障永远不会丢失数据。
  • 🧪 读取路径: FSDataInputStream 和 DFSInputStream 从 NameNode 获取块位置,然后直接从 DataNode 流式传输字节。
  • 🛠️ 写入路径: DFSOutputStream 将数据包排队,DataStreamer 构建 DataNode 管道,Ack 队列防止数据包丢失。
  • 🧭 访问选项: org.apache.hadoop.fs Java API 和 hdfs dfs shell 都支持打开、读取、写入和关闭操作。

HDFS 教程

什么是 HDFS?

HDFS 是一种分布式文件系统,用于存储超大型数据文件,运行在通用硬件集群上。它具有容错性、可扩展性,并且扩展起来极其简单。Hadoop 捆绑了 HDFS(Hadoop 分布式文件系统)。

当数据超出单台物理机器的存储容量时,将数据分散到多台独立的机器上就变得必不可少。管理跨机器网络的存储特定操作的文件系统称为分布式文件系统。HDFS 就是这样一种软件。

高密度文件系统 Archi质地

HDFS集群主要由以下部分组成: 名称节点 它管理文件系统元数据和 数据节点 存储实际数据的地方。

  • 名称节点: 名称节点(NameNode)可以被视为系统的主节点。它维护文件系统树以及系统中所有文件和目录的元数据。“命名空间映像”和“编辑日志”这两个文件用于存储元数据信息。名称节点知道给定文件的所有数据节点(DataNode)的数据块位置,但它不会持久存储数据块位置。每次系统启动时,这些信息都会从数据节点重新构建。
  • 数据节点: 数据节点是从节点,它们驻留在集群中的每台机器上,提供实际的存储功能。它们负责处理来自客户端的读写请求。

因为单个 NameNode 会成为单点故障,所以目前的集群运行一个活动 NameNode 和一个备用 NameNode,它们通过一组 JournalNode 共享编辑日志,并在两者之间进行自动故障转移。

HDFS 中的读写操作以块为单位进行。HDFS 中的数据文件被分割成块大小的数据块,这些数据块作为独立的单元存储。Hadoop 1.x 中的默认块大小为 64 MB。从 Hadoop 2.x 开始,默认值为 64 MB。 dfs.blocksize 是 128 MB。

HDFS 基于数据复制的概念运行,即创建多个数据块副本并将其分布在集群中的各个节点上,从而在节点发生故障时实现数据的高可用性。默认复制因子为 3(dfs复制当 DataNode 停止发送心跳时,NameNode 会自动将其数据块复制到其他地方。

你知道吗? HDFS 中小于单个块的文件不会占用一个块的全部存储空间。

了解 OperaHDFS 中的

数据读取请求由 HDFS、NameNode 和 DataNode 共同处理。我们将读取请求的节点称为“客户端”。下图展示了 Hadoop 中的文件读取操作。

HDFS读取操作的数据流在客户端、NameNode和DataNode之间流动

  1. 客户端通过调用 FileSystem 对象的 'open()' 方法发起读取请求;FileSystem 对象是 DistributedFileSystem 类型的对象。
  2. 此对象使用 RPC 连接到 NameNode,并获取元数据信息,例如文件块的位置。请注意,这些地址是文件前几个块的地址。
  3. 针对此元数据请求,将返回拥有该数据块副本的数据节点的地址。
  4. 一旦接收到数据节点的地址,就会向客户端返回一个 FSDataInputStream 类型的对象。FSDataInputStream 包含 DFSInputStream,后者负责处理与数据节点和名称节点的交互。在上图所示的步骤 4 中,客户端调用 `read()` 方法,该方法会使 DFSInputStream 与持有文件第一个数据块的第一个数据节点建立连接。
  5. 数据以流的形式读取,客户端会反复调用 `read()` 方法。`read()` 操作会一直持续到代码块结束。
  6. 当到达一个数据块的末尾时,DFSInputStream 会关闭连接并继续寻找下一个数据块的下一个 DataNode。
  7. 客户端读取完毕后,会调用 close() 方法。

填写 OperaHDFS 中的

在本节中,我们将了解如何通过文件将数据写入 HDFS。下图所示。 traces 写入路径。

使用 DataQueue、DataStreamer 和确认队列的 HDFS 写入操作管道

  1. 客户端通过调用 DistributedFileSystem 对象的 'create()' 方法发起写入操作,该方法创建一个新文件——上图中的步骤 1。
  2. DistributedFileSystem 对象通过 RPC 调用连接到 NameNode 并启动新文件创建操作。但是,此文件创建操作不会将任何数据块与该文件关联。NameNode 负责验证要创建的文件是否已存在,以及客户端是否拥有创建新文件的正确权限。如果文件已存在或客户端没有足够的权限创建新文件,则会向客户端抛出 IOException 异常。否则,操作成功,NameNode 会为该文件创建一个新记录。
  3. 在 NameNode 中创建新记录后,会向客户端返回一个 FSDataOutputStream 类型的对象。客户端使用该对象将数据写入 HDFS。然后调用数据写入方法(图中步骤 3)。
  4. FSDataOutputStream 包含一个 DFSOutputStream 对象,该对象负责与数据节点 (DataNode) 和名称节点 (NameNode) 进行通信。当客户端持续写入数据时,DFSOutputStream 会持续创建包含这些数据的包。这些包会被放入一个名为 DataQueue 的队列中。
  5. 还有一个名为 DataStreamer 的组件,它会使用这个 DataQueue。DataStreamer 还会向 NameNode 请求分配新的数据块,从而选择合适的 DataNode 用于数据复制。
  6. 现在,复制过程通过使用 DataNodes 创建管道开始。在我们的例子中,我们选择了 3 级复制,因此管道中有 3 个 DataNodes。
  7. DataStreamer 将数据包倒入管道中的第一个 DataNode。
  8. 管道中的每个数据节点都会存储它接收到的数据包,并将该数据包转发给管道中的第二个数据节点。
  9. DFSOutputStream 维护着另一个队列“确认队列”,用于存储等待数据节点确认的数据包。
  10. 一旦从管道中的所有 DataNode 收到队列中数据包的确认,该数据包就会从“确认队列”中删除。如果发生任何 DataNode 故障,则可以使用此队列中的数据包重新启动操作。
  11. 客户端完成数据写入后,会调用 close() 方法(图中步骤 9)。调用 close() 会将剩余的数据包刷新到管道中,然后等待确认。
  12. 一旦收到最终确认,就会联系 NameNode,告知其文件写入操作已完成。

使用以下方式访问 HDFS Java API

在本节中,我们尝试理解…… Java 用于访问Hadoop文件系统的接口。

为了以编程方式与Hadoop的文件系统交互,Hadoop提供了多种方法。 Java 类。名为 org.apache.hadoop.fs 的包包含用于操作 Hadoop 文件系统中文件的类。这些操作包括打开、读取、写入和关闭。Hadoop 文件 API 是通用的,可以扩展以与 HDFS 以外的文件系统进行交互。

以编程方式从 HDFS 读取文件

对象 java.net。URL 用于读取文件内容。首先,我们需要 Java 识别Hadoop的hdfs URL 方案。这是通过调用集合来实现的。URLStreamHandlerFactory 方法 URL 对象并向其传递 FsUrlStreamHandlerFactory 的实例。此方法只需执行一次。 JVM,因此它被包含在静态块中。

示例代码如下:

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }
    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

这段代码打开并读取一个文件的内容。该文件在HDFS上的路径作为命令行参数传递给程序。

使用命令行界面访问 HDFS

这是与HDFS交互的最简单方法之一。命令行界面支持文件系统操作,例如读取文件、创建目录、移动文件、删除数据和列出目录。

我们可以运行 '$HADOOP_HOME/bin/hdfs dfs-帮助' 要获取每个命令的详细帮助,请参阅相关文档。这里,“dfs”是HDFS的一个shell命令,它支持多个子命令。在当前的Hadoop版本中 HDFS DFS 是首选形式,而旧形式 Hadoop 文件系统 该命令对任何受支持的文件系统执行相同的工作。

下面列出了一些广泛使用的命令以及每个命令的一些详细信息。

1. 将文件从本地文件系统复制到 HDFS

$HADOOP_HOME/bin/hdfs dfs -copyFromLocal temp.txt /

此命令将文件 temp.txt 从本地文件系统复制到 HDFS,如下面的输出所示。

使用 hdfs dfs -copyFromLocal 命令将 temp.txt 复制到 HDFS。

2. 我们可以使用 -ls 参数列出目录中的文件。

$HADOOP_HOME/bin/hdfs dfs -ls /

在下面的列表中,我们可以看到“/”目录下的文件“temp.txt”(之前复制的)。

hdfs dfs -ls 命令输出 HDFS 根目录中的 temp.txt 文件。

3.将文件从 HDFS 复制到本地文件系统的命令

$HADOOP_HOME/bin/hdfs dfs -copyToLocal /temp.txt

此命令与 -get 命令类似,并接受一个显式的本地目标路径作为第二个参数。以下输出显示 temp.txt 已复制到本地文件系统。

hdfs dfs -copyToLocal 输出显示 temp.txt 已复制到本地文件系统

4. 创建新目录的命令

$HADOOP_HOME/bin/hdfs dfs -mkdir /mydirectory

该命令会静默完成,如下提示所示。

使用 hdfs dfs -mkdir 命令在 HDFS 中创建 /mydirectory 文件夹。

检查目录是否已创建。现在,你应该知道该怎么做了😉

常见问题

大数据块可以保持 NameNode 元数据较小,并允许映射器在再次寻道前读取较长的连续字节。因此,磁盘寻道时间仅占传输时间的一小部分,这使得全文件扫描速度很快。

NameNode停止接收心跳信号,将节点标记为死亡,并将所有低于其复制因子的数据块重新复制到健康的DataNode上。正在写入的数据会从确认队列中恢复,因此客户端不会丢失数据包。

未在正确配置的集群中运行。HDFS 高可用性运行一个活动 NameNode 和一个备用 NameNode,它们通过 JournalNode 共享编辑内容,而 ZooKeeper 故障转移控制器会在活动节点停止响应时自动将备用节点提升为活动节点。

两者都将数据上传到 HDFS。`-copyFromLocal` 选项将源限制为本地文件系统,而 `-put` 接受任何受支持的源,包括另一个 HDFS 路径或标准输入。除此之外,两者的行为完全相同,因此 `-copyFromLocal` 只是用来说明其用途。

在名称节点 (NameNode) 中,每个文件、目录和数据块都会占用内存,因此数百万个小文件会在磁盘空间耗尽之前就耗尽堆内存。将它们组合成序列文件、Avro、ORC、Parquet 或 HAR 归档文件,可以保持元数据的可管理性。

复制机制会保留三个完整副本,需要额外消耗 200% 的存储空间。Hadoop 3 中新增的纠删码则存储奇偶校验单元,在大约 50% 的额外开销下即可达到类似的持久性,其代价是在恢复期间更高的 CPU 和网络成本。

基于NameNode审计日志和DataNode指标训练的机器学习模型可以预测容量耗尽情况、标记热点块,并在磁盘故障前检测到它们。对访问模式的异常检测还可以及早发现失控作业。

Copilot 可以快速完成常见的 org.apache.hadoop.fs 样板代码,例如 FileSystem.get、FSDataInputStream 循环和 IOUtils.copyBytes 调用。请务必根据所使用的 Hadoop 版本验证生成的代码,因为 Hadoop 2.x 和 3.x 之间的 API 名称和已弃用的方法存在显著差异。

总结一下这篇文章: