跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
Javajava算法

分布式文件系统 HDFS 数据读写过程详解

HDFS 读写数据涉及客户端与 NameNode、DataNode 交互。读数据时客户端通过 FileSystem.open() 获取 DFSInputStream,查询块位置并选择最近节点读取,逐块完成。写数据时通过 FileSystem.create() 获取 DFSOutputStream,NameNode 创建文件元数据,客户端分包写入管道,DataNode 间传输并回传 ACK,最后通知 NameNode 关闭文件。

PentesterX发布于 2026/3/26更新于 2026/5/1210 浏览
分布式文件系统 HDFS 数据读写过程详解

一、读数据的过程

在介绍 HDFS 的数据读写过程之前,需要简单介绍一下相关的类。FileSystem 是一个通用文件系统的抽象基类,可以被分布式文件系统继承,所有可能使用 Hadoop 文件系统的代码都要使用到这个类。Hadoop 为 FileSystem 这个抽象类提供了多种具体的实现,DistributedFileSystem 就是 FileSystem 在 HDFS 中的实现。FileSystem 的 open() 方法返回的是一个输入流 FSDataInputStream 对象,在 HDFS 中具体的输入流就是 DFSInputStream;FileSystem 中的 create() 方法返回的是一个输出流 FSDataOutputStream 对象,在 HDFS 中具体的输出流就是 DFSOutputStream。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Chapter3 {
    public static void main(String[] args) {
        try {
            Configuration conf = new Configuration();
            conf.set("fs.defaultFS", "hdfs://localhost:9000");
            conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
            FileSystem fs = FileSystem.get(conf);
            Path file = new Path("test");
            FSDataInputStream getIt = fs.open(file);
            BufferedReader d = new BufferedReader(new InputStreamReader(getIt));
            String content = d.readLine(); // 读取文件一行
            System.out.println(content);
            d.close(); // 关闭文件
            fs.close(); // 关闭 hdfs
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://localhost:9000");
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
FileSystem fs = FileSystem.get(conf);
FSDataInputStream in = fs.open(new Path(uri));
FSDataOutputStream out = fs.create(new Path(uri));

客户端连续调用 open()、read()、close() 读取数据时,HDFS 内部的执行过程如下图 1。

在这里插入图片描述

图 1 HDFS 读数据的过程

  1. 客户端通过 FileSystem.open() 打开文件,相应地,在 HDFS 中 DistributedFileSystem 具体实现了 FileSystem。因此,调用 open() 方法后,DistributedFileSystem 会创建输入流 FSDataInputStream,对于 HDFS 而言,具体的输入流就是 DFSInputStream。
  2. 在 DFSInputStream 的构造函数中,输入流通过 ClientProtocal.getBlockLocations() 远程调用名称节点,获得文件开始部分数据块的保存位置。对于该数据块,名称节点返回保存该数据块的所有数据节点的地址,同时根据距离客户端的远近对数据节点进行排序;然后,DistributedFileSystem 会利用 DFSInputStream 来实例化 FSDataInputStream,并返回给客户端,同时返回数据块的数据节点地址。
  3. 获得输入流 FSDataInputStream 后,客户端调用 read() 方法开始读取数据。输入流根据前面的排序结果,选择距离客户端最近的数据节点建立连接并读取数据。
  4. 数据从该数据节点读到客户端;当该数据块读取完毕时,FSDataInputStream 关闭和该数据节点的连接。
  5. 输入流通过 getBlockLocations() 方法查找下一个数据块(如果客户端缓存中已经包含了该数据块的位置信息,就不需要调用该方法)。
  6. 找到该数据块的最佳数据节点,读取数据。
  7. 当客户端读取完数据的时候,调用 FSDataInputStream 的 close() 方法,关闭输入流。需要注意的是,在读取数据的过程中,如果客户端与数据节点通信时出现错误,就会尝试连接包含此数据块的下一个数据节点。

二、写数据的过程

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class Chapter3 {
    public static void main(String[] args) {
        try {
            Configuration conf = new Configuration();
            conf.set("fs.defaultFS", "hdfs://localhost:9000");
            conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
            FileSystem fs = FileSystem.get(conf);
            byte[] buff = "Hello world".getBytes(); // 要写入的内容
            String filename = "test"; // 要写入的文件名
            FSDataOutputStream os = fs.create(new Path(filename));
            os.write(buff, 0, buff.length);
            System.out.println("Create:" + filename);
            os.close();
            fs.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

客户端向 HDFS 写数据是一个复杂的过程,这里介绍一下在不发生任何异常的情况下,客户端连续调用 create()、write() 和 close() 时,HDFS 内部的执行过程见图 2。

在这里插入图片描述

图 2 HDFS 写数据的过程

  1. 客户端通过 FileSystem.create() 创建文件,相应地,在 HDFS 中 DistributedFileSystem 具体实现了 FileSystem。因此,调用 create() 方法后,DistributedFileSystem 会创建输出流 FSDataOutputStream,对于 HDFS 而言,具体的输出流就是 DFSOutputStream。
  2. 然后,DistributedFileSystem 通过 RPC 远程调用名称节点,在文件系统的命名空间中创建一个新的文件。名称节点会执行一些检查,比如文件是否已经存在,客户端是否有权限创建文件等。检查通过之后,名称节点会构造一个新文件,并添加文件信息。远程方法调用结束后,DistributedFileSystem 会利用 DFSOutputStream 来实例化 FSDataOutputStream,并返回给客户端,客户端使用这个输出流写入数据。
  3. 获得输出流 FSDataOutputStream 以后,客户端调用输出流的 write() 方法向 HDFS 中对应的文件写入数据。
  4. 客户端向输出流 FSDataOutputStream 中写入的数据会首先被分成一个个的分包,这些分包被放入 DFSOutputStream 对象的内部队列。输出流 FSDataOutputStream 会向名称节点申请保存文件和副本数据块的若干个数据节点,这些数据节点形成一个数据流管道。队列中的分包最后被打包成数据包,发往数据流管道中的第 1 个数据节点,第 1 个数据节点将数据包发送给第 2 个数据节点,第 2 个数据节点将数据包发送给第 3 个数据节点,这样,数据包会流经管道上的各个数据节点。
  5. 因为各个数据节点位于不同的机器上,数据需要通过网络发送。因此,为了保证所有数据节点的数据都是准确的,接收到数据的数据节点要向发送者发送'确认包'(ACK Packet)。确认包沿着数据流管道逆流而上,从数据流管道依次经过各个数据节点并最终发往客户端,当客户端收到应答时,它将对应的分包从内部队列移除。不断执行 3~5 步,直到数据全部写完。
  6. 客户端调用 close() 方法关闭输出流,此时开始,客户端不会再向输出流中写入数据,所以,当 DFSOutputStream 对象内部队列中的分包都收到应答以后,就可以使用 ClientProtocol.complete() 方法通知名称节点关闭文件,完成一次正常的写文件过程。

小结

HDFS 读写数据时,读数据通过 FileSystem.open() 创建 DFSInputStream,获取数据块位置,选择最近数据节点读取,读完关闭连接并查找下一数据块;写数据则通过 FileSystem.create() 创建 DFSOutputStream,远程调用名称节点创建文件,写入数据时分包放入队列,形成数据流管道传输,数据节点发送确认包,全部写完客户端调用 close() 关闭输出流,通知名称节点关闭文件,从而完成 HDFS 数据正常读写过程。

目录

  1. 一、读数据的过程
  2. 二、写数据的过程
  3. 小结
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • GitHub 界面中文化插件使用指南
  • Web 项目 UI 自动化测试实战:从零搭建博客系统测试框架
  • 2.5D 等距透视废墟建筑 AIGC 辅助量产工作流
  • 二分答案专题实战:木材加工与砍树问题详解
  • HDFS 分布式文件系统数据读写流程详解
  • ESLint 深度指南:从原理配置到工程化实践
  • Web 项目 UI 自动化测试实战:从零搭建博客系统框架
  • 5 款主流开源 AI Agent 框架深度解析
  • 大型语言模型的 11 种高效微调策略详解
  • Java 基础:Scanner 类用法详解
  • Python 开发环境搭建与常用工具配置指南
  • 黑客入门教程:安全工程师能力要求与学习路线
  • 链表经典算法实战:相交、回文与随机指针复制
  • LLM Agent 指令微调与搜索代理方案
  • 算法优选:位运算实战技巧与经典例题解析
  • 本地部署 Llama3 大模型与 Open WebUI 界面教程
  • C++ 异常机制详解与实践指南
  • Llama Factory 大模型微调显存优化技巧
  • AI 代码助手对比:CodeGeex、RooCode 与 GitHub Copilot
  • C++ 深入:类与对象的默认成员函数及运算符重载

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online