HDFS 读、写流程
一、HDFS 写入文件(上传本地文件到 HDFS,比如hdfs dfs -put)
人物: 客户端(你敲命令的终端)、NameNode(管家)、DataNode(三台服务器仓库)
- 你执行上传命令,客户端先找 NameNode 管家:我要新建一个文件,行不行?
- NameNode 检查路径、权限没问题,在自己的记录簿(edits 日志)写下:这里新建空文件,返回允许写入。
- 客户端把你的大文件切成一小段一小段数据包(Packet),准备发给仓库。
- HDFS 副本规则 3 份,管家告诉客户端:第一个块发给 hadoop1,副本存 hadoop2、hadoop3。
- 流水线传输:数据包先发给 hadoop1,hadoop1 存完立刻转发给 hadoop2,hadoop2 再转发给 hadoop3,三台同时存副本。
- 每台存好之后,会反向给客户端发 “确认收到” 的回执包。
- 一段数据包三台都存完,再发下一段,循环直到整个文件传完。
- 全部数据传完,客户端通知 NameNode:文件上传完毕。管家更新日志,这个文件才算正式存在 HDFS 里。
简单总结写流程:客户端切块 → 问管家权限 → 流水线多节点存 3 副本 → 全部传完告知管家归档。
二、HDFS 读取文件(下载 / 查看hdfs dfs -cat)
- 客户端想读文件,先找 NameNode 管家:我要读 xx 文件,这个文件的数据块在哪几台机器?
- NameNode 翻自己的记录,把所有块对应的三台 DataNode 地址全部发给客户端,优先给离你近、本机有副本的节点(本地优先,少走网络)。
- 客户端直接连接对应 DataNode,拉取对应块的数据,全程不用再麻烦 NameNode,管家只负责指路,不传输真实数据。
- 一块数据读完,自动连接下一个块的服务器继续读取。
- 如果某台 DataNode 连不上、数据损坏,客户端自动换同块其他副本服务器读取,不会报错中断。
- 所有块读取拼接完成,关闭连接,读取结束。
简单总结读流程:找管家拿数据块位置 → 直连 DataNode 拿数据 → 坏节点自动换副本。
三、HDFS 存储 Block、上传 Packet、MR 的 Split 三者区分
1. HDFS 底层 Block(物理数据块)
- 定义:文件上传完成后,持久保存在 DataNode 磁盘的存储单元,Hadoop2.6 默认 64M。
- 共性:普通读取文件、MR 程序读取,操作的底层 Block 是同一个物理块。
两种读取的不同处理逻辑
1)hdfs dfs -cat/ 下载文件 客户端从 NN 获取每个 Block 存放节点,依次读取所有 Block,把数据拼接成完整原始文件展示,仅做数据读取,不会生成计算任务。
2)运行 MapReduce 程序 MR 读取磁盘上同一个 Block,将每一个 Block 封装成 InputSplit 分片,分配独立 MapTask 并行计算,读取后不拼接完整文件,输出中间键值到本地磁盘。
示例:120M 文件,HDFS 生成 2 个 Block(64M+56M)
- cat 读取:两块拼接,输出完整原文;
- WordCount:2 个 Block 对应 2 个 Split,启动 2 个 Map 任务统计单词。
2. 上传时 Packet(网络传输小包)
文件put上传阶段专用,客户端把文件切分成小型 Packet 数据包,用于流水线 Pipeline 多副本传输。 Packet 只是传输过程临时拆分,传输完成后会合并成完整 Block 存磁盘,Packet 只负责网络发送,不会影响后续 MR 任务数量。
3. MR 的 InputSplit(计算分片)
仅运行计算程序时临时划分,默认一个 Block 对应一个 Split,每一个 Split 对应一个 MapTask。 Split 是逻辑划分,不会修改磁盘上真实 Block,只用来分配计算数据、决定 Map 任务数量。
核心总结
- 磁盘真实存储单元:Block,读文件、跑 MR 共用;
- 上传传输临时拆分:Packet,仅上传阶段使用;
- 计算逻辑分片:Split,MR 运行时基于 Block 生成,用来分配 Map 任务; Packet、Split 只是过程拆分,底层存储载体统一都是 Block。
