Hadoop —— HDFS 写数据流程

一、全部组件名词深度解析

(1)客户端侧组件

HDFS Client

HDFS 客户端,属于一套代码库,不是独立进程。命令行、Java 代码上传文件本质就是加载这套客户端库。

主要职责:

  • 读取本地磁盘源文件;
  • 逻辑切分文件为 Block 块;
  • 与 NameNode 进行 RPC 远程通信,获取元数据、获取 DataNode 节点列表;
  • 和 DataNode 建立网络连接,切分 Packet 数据包、发送数据;
  • 接收 DataNode 返回 ACK 确认包,处理失败重传;
  • 维护 FSDataOutputStream 输出流对象。

DistributedFileSystem

HDFS Java API 的核心类,实现 FileSystem 抽象父类。客户端与 NameNode 之间所有 RPC 远程调用,全部由该类完成。

注意:它不传输真实文件字节数据,只传输控制指令:创建文件、获取块节点、通知上传完成。

create() 方法

API 调用:DistributedFileSystem.create(path)。作用:向 NameNode 发送 RPC 请求,在 HDFS 指定路径新建文件。NameNode 校验通过之后,该方法返回输出流对象 FSDataOutputStream。

FSDataOutputStream

文件系统数据输出流。真正负责向外写出文件数据的对象。DistributedFileSystem 只负责控制命令;真实文件数据全部交给 FSDataOutputStream 处理。

内部封装逻辑:

  • 维护数据包队列,将文件数据切割成 Packet;
  • 维护应答队列,接收流水线传回 ACK 确认包;
  • 管理 Pipeline 流水线网络连接;
  • 处理 DataNode 故障,故障时剔除节点重建流水线;
  • write():把本地字节写入流内存缓冲区;
  • close():数据写完关闭流,发送 complete 通知 NameNode。

write()

写方法。程序调用 outputStream.write(byte\[\]),将本地文件字节写入输出流内存缓冲区。此时数据仅仅停留在客户端内存,还没有发送到网络。

close()

关闭输出流,非常关键。执行 close() 之后,客户端向 NameNode 发送 complete RPC 请求,告诉 NameNode 所有块上传结束,更新元数据。如果程序异常退出没有执行 close(),HDFS 只会保留临时未完成文件,其他客户端无法读取。

(2)NameNode(主节点 NN)

独立 Java 进程。

重点:NameNode 不接收、不存储任何真实文件内容字节,只处理元数据与调度,真实数据流只存在客户端和 DataNode 之间。

metadata 元数据

描述数据的数据。包含:HDFS 目录树、文件名、路径、权限、文件大小、Block 编号、每个 Block 存储在哪些 DataNode。元数据完整保存在 NameNode 内存,磁盘持久化为 fsimage 镜像文件、edits 编辑日志文件。

接收 create 创建请求时的两项校验

  • 权限校验:当前用户是否拥有目标目录创建文件权限;
  • 目录校验:文件父目录是否存在。

校验失败直接返回错误;校验成功,回复客户端允许上传文件。

块分配与机架感知原理

客户端申请 Block 存储节点列表时,NameNode 使用机架感知策略挑选 3 台 DataNode。默认副本放置策略:

  • 第 1 副本:客户端所在机器;客户端不在集群则随机选一台 DataNode;
  • 第 2 副本:另一个机架上的 DataNode;
  • 第 3 副本:和第 2 副本同机架,另一台不同机器。

目的:防止单个机架断电导致全部副本丢失,同时兼顾内网传输性能。NameNode 返回 DN1、DN2、DN3 三台节点地址给客户端。

注意:此时 NameNode 不会保存 Block 和 DN 的映射关系。块位置后续由 DataNode 通过心跳上报给 NameNode。

(3)DataNode(数据节点 DN1 DN2 DN3)

独立 Java 进程,真正存储 Block 真实业务数据。

bytebuffer 字节缓冲区

DataNode 机器内存区域。网络收到 Packet 数据包,先放入 bytebuffer 内存缓冲区,之后再刷写到磁盘生成 blk-1 块文件。

blk-1、blk-2

DataNode 磁盘上的二进制物理文件。blk-1 代表第一个数据块。Block:磁盘存储逻辑单位,默认 128MB,大文件逻辑切割分散存储。

Pipeline 流水线(Block 传输通道)

串联网络链路:客户端 → DN1 → DN2 → DN3。核心特点:客户端只发送一份 Packet 数据包给 DN1;DN1 落盘之后转发 Packet 给 DN2;DN2 落盘转发 Packet 给 DN3。优势:节省客户端出口带宽,副本复制交给 DataNode 内网完成。

Packet(64KB)

网络传输最小单元,默认大小 64KB。区分:Block (128MB) = 磁盘存储单位;Packet (64KB) = 网络传输小包。128MB 的 Block 会被拆分为大量 Packet 逐个传输。Packet 包含:业务数据、校验和、序列号。客户端维护发送队列、应答队列;收到 ACK 确认之后才删除 Packet;ACK 失败则重传数据包。

ACK 应答包(Acknowledge 确认响应)

传输方向:反向流水线。DN3 完成落盘生成 ACK,依次传给 DN2→DN1→客户端。客户端收到 ACK,代表该 Packet 在 3 台 DataNode 全部持久化成功。遇到 DN 故障时,流水线剔除故障节点,剩余节点继续传输。

二、HDFS 写流程 8 步完整运行过程

上传 HDFS 路径:/root/gateway_records.txt,本地源文件 200MB。

步骤 1:客户端发起创建文件 RPC 请求

调用 DistributedFileSystem.create("/root/gateway_records.txt"),DistributedFileSystem 组件向 NameNode 发送 RPC 请求。NameNode 执行校验:检查父目录 /root 是否存在;检查客户端用户是否具备创建文件权限。此时 HDFS 无真实文件,NameNode 仅生成临时元数据记录,文件状态标记为"正在写入",还没有真实数据流动。

步骤 2:NameNode 返回上传许可

校验全部通过,RPC 回复客户端允许上传。create() 方法返回 FSDataOutputStream 输出流对象,后续写数据全部使用该输出流。

步骤 3:客户端请求第一个 Block 对应的 DataNode 列表

准备上传第一个 Block blk-1(0-128MB)。客户端 RPC 请求 NameNode,获取存放该 Block 副本的 3 台 DataNode 节点。NameNode 执行机架感知策略,筛选健康节点 DN1、DN2、DN3。

步骤 4:NameNode 返回 DN1、DN2、DN3 节点地址

NameNode 将三台 DataNode 的 IP 与端口返回客户端。此时 NameNode 内存还不会记录 Block 与 DN 的对应关系。

步骤 5:建立 Pipeline 流水线 TCP 网络通道

FSDataOutputStream 建立网络连接:客户端建立 TCP 连接到 DN1;DN1 收到连接请求,内部建立 TCP 连接连接下游 DN2;DN2 收到连接请求,内部建立 TCP 连接连接下游 DN3。完整流水线链路:客户端 → DN1 → DN2 → DN3,通道建立完成。

步骤 6:逐级 ACK 应答确认流水线就绪

确认消息从链路末尾 DN3 反向往客户端传递:DN3 连接就绪,发送 ACK 给 DN2;DN2 收到 DN3 的 ACK,发送 ACK 给 DN1;DN1 收到 DN2 的 ACK,发送 ACK 给客户端。客户端收到 ACK,整条流水线就绪,可以传输真实 Packet 数据。如果任意节点连接失败,客户端重新向 NameNode 申请新 DataNode 重建流水线。

步骤 7:以 Packet 为单位传输 blk-1(0-128MB)

客户端读取本地 200MB 文件,调用 FSDataOutputStream.write() 写入数据,数据存放在客户端内存缓冲区。缓冲区攒够 64KB,封装为 Packet 数据包,进入发送队列。客户端将 Packet 发送给 DN1。DN1 接收 Packet:放入 bytebuffer 缓冲区;写入本地磁盘 blk-1;转发 Packet 给下游 DN2。DN2 接收 Packet:放入 bytebuffer 缓冲区;写入本地磁盘 blk-1;转发 Packet 给下游 DN3。DN3 接收 Packet:放入 bytebuffer 缓冲区;写入本地磁盘 blk-1;无下游节点,停止转发,生成 ACK 确认包反向传回。ACK 沿着 DN3→DN2→DN1→客户端路径返回。客户端收到 ACK,代表 Packet 三份副本落盘成功,从应答队列移除 Packet。循环发送 Packet,直到完整 128MB blk-1 块全部传输完毕并且全部收到 ACK 确认。

步骤 8:循环处理剩余 Block 块,close 完成上传

blk-1 全部传输完成。客户端再次 RPC 请求 NameNode,获取第二个 Block blk-2(72MB)的 DataNode 节点列表。重复步骤 5-7,建立流水线传输 blk-2 所有 Packet。blk-2 传输完毕,所有块处理完成。客户端调用 FSDataOutputStream.close() 关闭输出流。close 内部发送 complete RPC 请求通知 NameNode 文件上传全部完成。NameNode 修改元数据,文件状态由"正在写入"修改为正常完成状态,HDFS 上 /root/gateway_records.txt 文件正式生效,可以被读取。

补充:各个 DataNode 定期心跳上报本机保存的 Block 编号给 NameNode,NameNode 才填充 Block 与 DataNode 位置映射。

三、底层补充细节

CheckSum 校验和

每个 Packet 携带校验和。DataNode 收到数据包进行校验,检测网络传输数据损坏,出错返回错误 ACK。

DataNode 故障处理

传输过程中某个 DataNode 宕机,客户端收不到对应 ACK。客户端剔除故障节点,剩余可用节点继续完成当前块传输。后续 NameNode 检测副本数量不足,后台自动复制补齐 3 副本。

Block 与 Packet 差异

Block(128MB):面向磁盘存储,减少 NameNode 元数据条目;Packet(64KB):面向网络传输,流式发送、及时确认,不需要等待完整块读完。

数据流隔离

真实文件字节流只在客户端与 DataNode 之间传输;NameNode 只处理 RPC 控制消息,不转发业务数据,保障 NameNode 性能。

相关推荐
磁场转动100万匹1 小时前
大数据入门:Hadoop 与 MapReduce 学习路线
大数据·hadoop·mapreduce
陈年老古董1 小时前
Python模拟MapReduce分治思想 | 从单文件统计到大文件拆分聚合 学习笔记
开发语言·hadoop·笔记·python·学习
明志数科1 小时前
具身智能数据工程观察:从集中式数采工厂到真实场景采集,数据供给路线正在转向
大数据·数据库·人工智能
天行健,君子而铎1 小时前
数据分类分级的范式转换:从规则匹配到模型持续优化规模化前瞻算法
大数据·网络·数据库·安全·分类
AI早餐汇1 小时前
京东高级副总裁胡喜:零售企业AI变革之路的探索与实践
大数据·人工智能·零售
2601_962780911 小时前
2026 秋招金融风控岗位能力拆解:数据分析、工具、项目与证书备考方案
大数据·人工智能
TKcloudmaster_H1 小时前
告别低效运营:跨境数据分析 + 多账号矩阵增效方案
大数据·矩阵·数据挖掘·数据分析·新媒体运营·产品运营·流量运营
涛思数据(TDengine)2 小时前
存储成本降低80%,Zendure用TDengine支撑117万台设备的能源数据分析
大数据·数据库·人工智能·数据分析·时序数据库·tdengine·工业
shirsl2 小时前
数据开发每日面试题 Day 1
大数据·数据库·sql·big data