第4章 Hadoop分布式文件系统
HDFS 为什么这么设计、数据怎么保证不丢、一次读和一次写各自经历了什么。
本章学习目标
- 能说出 HDFS 的设计目标与不足
- 能画出 HDFS 体系结构(NameNode / DataNode / Client)
- 能说明副本机制、心跳机制、机架感知与安全模式
- 能完整描述 HDFS 读流程与写流程
- 能用命令行和 Java API 操作 HDFS
本章导览
核心内容
HDFS概述
HDFS(Hadoop Distributed File System)是为"一次写入、多次读取"的超大文件设计的分布式文件系统。
HDFS的设计目标和不足
| 目标 | 实现方式 |
|---|---|
| 超大文件存储 | 文件切块(默认 128MB)+ 多节点存放 |
| 硬件容错 | 数据多副本,节点故障自动切换 |
| 流式数据访问 | 顺序读为主,高吞吐优于低延迟 |
| 简单一致性模型 | 一次写入多次读取,不支持随机修改 |
- 不足一:不适合低延迟访问(毫秒级查询请用 HBase)
- 不足二:不适合大量小文件(NameNode 内存压力)
- 不足三:不支持多用户并发写入同一文件
HDFS的体系结构
| 角色 | 职责 | 数量 |
|---|---|---|
| NameNode | 管理元数据(目录树、文件与块的映射、块位置) | 1(HA 下 2) |
| DataNode | 实际存储数据块,定期向 NN 汇报块列表 | 多 |
| SecondaryNameNode | 定期合并 FsImage 与 EditLog(不是备份) | 1 |
| Client | 切分文件、与 NN 交互获取块位置、直接读写 DN | 多 |
数据错误与恢复
HDFS 假设"硬件一定会坏",所以把容错做进了每个环节。
block损坏处理
- 写数据时客户端计算校验和,DataNode 存校验和并随块一起保存
- 读取时客户端比对校验和,不一致说明块损坏
- 客户端自动向 NameNode 报告坏块,改从其它副本读取
- NameNode 标记该块副本失效,并从其它副本复制一份补齐
NameNode和DataNode错误处理
- DataNode 故障:心跳超时(默认 10.5 分钟)判定死亡,副本数不足则自动补副本
- NameNode 故障:HA 架构下 Standby 通过 ZooKeeper 选举接管;非 HA 需手工恢复 FsImage
- 元数据安全:通过 <code class="inl">fsimage</code> + <code class="inl">edits</code> 持久化,SecondaryNameNode 定期合并
HDFS的运行机制
这一节是全章的理论核心,也是笔试高频考点。
| 机制 | 一句话解释 |
|---|---|
| 副本机制 | 每个块默认存 3 份,分布在不同节点/机架 |
| 心跳机制 | DataNode 每 3 秒向 NameNode 汇报,超时判死 |
| 机架感知 | 副本按"本机架 1 份 + 异地架 2 份"放置,兼顾性能与容错 |
| Federation | 多个 NameNode 各管一部分命名空间,解决单 NN 内存瓶颈 |
| HA | Active/Standby 双 NN,靠 JournalNode + ZooKeeper 实现秒级切换 |
| 安全模式 | 启动时只读校验块,不接收写操作 |
| 垃圾回收 | 删除的文件先进 /trash,超时(默认 6 小时)才真正删除 |
# 安全模式相关命令
hdfs dfsadmin -safemode get # 查看是否在安全模式
hdfs dfsadmin -safemode leave # 强制退出(块缺失时可临时救急)
# 副本数与机架感知
hdfs dfs -setrep -w 3 /data/a.txt
hdfs dfsadmin -printTopologyHDFS的工作流程
教材把流程拆成启动、读、写、删除四段,建议背下写流程的七个步骤——面试几乎必问。
HDFS写流程
- ① Client 调用 create() 向 NameNode 请求创建文件
- ② NameNode 校验权限与是否已存在,返回可写状态
- ③ Client 请求第一个 block 的 DataNode 列表
- ④ 返回的 DataNode 组成 pipeline,Client 开始写第一个节点
- ⑤ 数据包沿 pipeline 逐级传递并写入磁盘
- ⑥ 每个节点写完回 ACK,逐级回传
- ⑦ 文件写完,Client 通知 NameNode 关闭文件(complete)
HDFS读流程
- ① Client 向 NameNode 请求打开文件
- ② NameNode 返回该文件所有 block 所在的 DataNode 列表(按距离排序)
- ③ Client 选择最近的 DataNode 读取数据块
- ④ 读取完成关闭连接
- ⑤ 依次读取下一个 block,直到读完
💡 读流程不经过 NameNode 传数据,NameNode 只给"地图",数据直接由 DataNode 到 Client——这是 HDFS 能支撑高吞吐的关键设计。
HDFS的基本操作
命令行最常用,Java API 是后续 MapReduce 编程的基础。
HDFS命令行操作
| 命令 | 作用 |
|---|---|
| hdfs dfs -ls / | 查看目录 |
| hdfs dfs -mkdir -p /a/b | 递归创建目录 |
| hdfs dfs -put 本地文件 /路径 | 上传(等价 -copyFromLocal) |
| hdfs dfs -get /路径 本地 | 下载(等价 -copyToLocal) |
| hdfs dfs -cat /文件 | 查看内容 |
| hdfs dfs -du -h /路径 | 查看大小 |
| hdfs dfs -mv / -cp / -rm -r | 移动 / 复制 / 删除 |
| hdfs dfs -chmod -R 777 /路径 | 改权限 |
| hdfs dfs -expunge | 清空回收站 |
hdfs dfs -mkdir -p /data/input
hdfs dfs -put /home/hadoop/w.txt /data/input/
hdfs dfs -ls -h /data/input
hdfs dfs -cat /data/input/w.txt
hdfs dfs -du -h /data
hdfs dfs -rm -r /data/inputHDFS Java API操作
Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://hadoop1:9000");
FileSystem fs = FileSystem.get(conf);
// 上传
fs.copyFromLocalFile(new Path("D:/w.txt"), new Path("/data/input/w.txt"));
// 下载
fs.copyToLocalFile(new Path("/data/input/w.txt"), new Path("D:/out.txt"));
// 判断存在 / 列目录
System.out.println(fs.exists(new Path("/data/input")));
for (FileStatus s : fs.listStatus(new Path("/data"))) {
System.out.println(s.getPath() + " " + s.getLen());
}
fs.close();本章小结
本章先讲 HDFS 的设计目标与不足,再讲体系结构(NameNode/DataNode/SecondaryNameNode/Client),然后系统梳理了副本、心跳、机架感知、Federation、HA、安全模式、垃圾回收七大机制,重点展开读流程与写流程,最后给出命令行与 Java API 两套操作方式。
思考与练习 先自己做,再点开答案
HDFS 默认块大小是多少?为什么这么大?
查看参考答案
Hadoop 2.x/3.x 默认为 128MB(1.x 为 64MB)。块大可以降低寻址开销占比,让磁盘传输时间占主导,从而提高吞吐;同时减少 NameNode 需要管理的块数量。
SecondaryNameNode 是 NameNode 的备份吗?
查看参考答案
不是。它只负责定期把 NameNode 的 EditLog 合并进 FsImage,减轻 NameNode 启动时的合并压力。NameNode 真正的高可用要靠 HA(Standby NameNode + JournalNode + ZooKeeper)。
写一个 200MB 的文件,会切几个块?写流程经过哪些角色?
查看参考答案
按 128MB 切块,200MB = 128MB + 72MB,共 2 个块。流程:Client → NameNode 请求创建与块位置 → 按 pipeline 依次写入 DataNode1→2→3 → 各节点回 ACK → 全部写完通知 NameNode complete。
进入安全模式后为什么不能写数据?怎么退出?
查看参考答案
安全模式是 NameNode 启动时校验各 DataNode 块报告的过程,此时 HDFS 只读不写。查看 hdfs dfsadmin -safemode get,正常会自动退出;块缺失导致卡住时可 hdfs dfsadmin -safemode leave(需先确认数据可用)。