HDFS知识笔记
Hadoop HDFS分布式文件系统
一、HDFS 优缺点
HDFS 的设计目标是适配“大数据批处理”场景,因此优缺点具有明显的场景导向性。
1. 优点:适配大数据场景
- 支持超大规模数据:无论是数据量(PB 级甚至 EB 级)还是文件数量,HDFS 都能通过分布式架构高效承载。
- 高容错性:默认将数据自动保存 3 个副本,当某个副本因节点故障丢失时,HDFS 会自动从其他副本恢复,无需人工干预。
- 低成本部署:可构建在廉价的普通服务器上,通过软件层面的容错机制替代昂贵的硬件冗余,降低集群建设成本。
2. 缺点:不适合实时/小文件场景
- 存储大量小文件效率低:
- 内存开销大:NameNode 需存储所有文件的目录信息和块映射,小文件(如 KB 级)会导致元数据数量暴增,耗尽 NameNode 有限内存。
- 寻址效率低:小文件的“寻址时间”(定位块位置)会远超过“读取时间”,违背 HDFS“减少寻址、提升传输效率”的设计目标。
- 不支持并发写入与随机修改:
- 单文件不支持多线程并发写入,避免数据一致性问题。
- 仅支持“数据追加”(Append),不支持随机修改文件内容(如中间插入、删除数据)。
- 不支持低延迟访问:HDFS 设计初衷是“批处理”,无法满足毫秒级、秒级的实时数据读写需求(如在线数据库场景)。
二、HDFS 的组成架构
HDFS 采用主从(Master/Slave)架构,核心角色包括 NameNode(主节点)、DataNode(从节点)、Secondary NameNode(辅助节点)和 Client(客户端),各角色职责明确、协同工作。
角色 | 核心职责 | 地位 |
---|---|---|
NameNode(NN) | 1. 管理 HDFS 名称空间(目录、文件结构); 2. 配置副本策略(如默认 3 副本); 3. 维护数据块与 DataNode 的映射关系; 4. 处理客户端的读写请求(仅元数据层面) |
主节点,集群“大脑”,单点(需通过 HA 实现高可用) |
DataNode(DN) | 1. 存储实际的数据块(Block); 2. 执行数据块的读写操作; 3. 通过心跳向 NameNode 汇报自身状态 |
从节点,集群“存储节点”,可横向扩展 |
Secondary NameNode(2NN) | 1. 辅助 NN,定期合并 fsimage 和 edits 日志,减轻 NN 负担; 2. 紧急情况下(如 NN 宕机且无 HA),可辅助恢复 NN 元数据 |
辅助节点,非 NN 备用节点(HA 架构中被 JournalNode 替代) |
Client(客户端) | 1. 上传文件时切分文件为数据块; 2. 与 NN 交互获取文件位置,与 DN 交互读写数据; 3. 提供 HDFS 管理命令(如格式化 NN、增删文件) |
交互入口,非集群节点,可部署在集群内或外部 |
三、HDFS 写数据流程
HDFS 的写数据流程需协调 Client、NN、DN 三者,核心是“元数据校验→块切分→副本分配→流水线传输→元数据更新”,确保数据可靠存储。
1. 核心角色
- Client:发起写请求,切分文件为 Block,管理数据传输·流水线。
- NameNode:校验权限、分配 Block 存储位置(DataNode 列表),更新元数据。
- DataNode:存储 Block,参与流水线传输,通过心跳汇报状态。
2. 详细流程(7 步)
-
Client 发起写请求,NN 校验
Client 通过DistributedFileSystem
类向 NN 发送写文件请求(如hdfs dfs -put localfile /hdfs/path
),NN 校验以下内容:- Client 是否有目标路径的写入权限;
- 目标路径是否已存在同名文件(未设置覆盖则返回错误);
- 集群剩余空间是否满足文件大小(按“文件大小×副本数”计算)。
校验通过后,NN 返回“允许写入”。
-
Client 切分文件为 Block
Client 按 HDFS 默认块大小(128MB,可配置)将文件切分为 Block,例如 1GB 文件切分为 8 个 128MB Block(最后一块可能不足 128MB),并为每个 Block 分配唯一标识(如blk_1073741825
)。 -
Client 向 NN 申请 Block 存储位置
Client 逐个向 NN 请求“当前 Block 的存储位置”,NN 按副本放置策略分配 DataNode 列表(以 3 副本为例):- 第 1 副本:优先 Client 所在节点(若 Client 在集群内),否则同机架随机节点;
- 第 2 副本:与第 1 副本不同机架的随机节点(跨机架容错);
- 第 3 副本:与第 2 副本同机架的随机节点(平衡容错与网络开销)。
NN 返回分配的 DataNode 列表(如[DN1, DN2, DN3]
)。
-
建立数据传输流水线(Pipeline)
Client 与 DN1 建立 TCP 连接,DN1 再与 DN2 建立连接,DN2 与 DN3 建立连接,形成“Client→DN1→DN2→DN3”的流水线。连接建立后,DN3 向 Client 返回“准备就绪”确认。 -
Client 向流水线传输数据
Client 将 Block 拆分为更小的数据包(Packet,默认 64KB),放入本地缓冲区,通过流水线依次发送给 DN1:- DN1 接收后,一边写入本地磁盘,一边转发给 DN2;
- DN2 同理,一边写入本地,一边转发给 DN3;
- DN3 仅写入本地,不转发。
每个 Packet 传输完成后,下游节点会返回 ACK 确认,确保数据无误。
-
Block 写入完成,NN 更新元数据
当 Block 的所有 Packet 传输完成且 3 个副本均写入成功后:- Client 向 NN 发送“Block 写入完成”通知;
- NN 更新元数据(记录 Block 标识、所属文件、存储的 DN 列表等)。
-
重复流程至所有 Block 写入
Client 按顺序处理下一个 Block,重复步骤 3-6,直至所有 Block 写入完成。最后 Client 向 NN 发送“文件写入完成”请求,NN 更新文件元数据(如文件大小、块数量),并返回“写入成功”。
3. 关键保障机制
- 副本容错:若传输中某 DN 故障(如 DN2 宕机),Client 中断流水线,通知 NN 重新分配 DN4,从故障点重新传输未完成的 Packet,确保最终副本数达标。
- 数据校验:每个 Block 生成对应的校验和(Checksum),存储在
.blk_xxx.crc
文件中,读取时验证数据完整性,避免损坏数据被使用。
四、HDFS 读数据流程
读数据流程的核心是“元数据获取→最优 DN 选择→数据读取→块拼接”,通过“数据本地化”机制减少网络开销,提升读取效率。
1. 核心角色
- Client:发起读请求,选择最优 DN,拼接 Block 为完整文件。
- NameNode:校验权限,提供 Block 与 DN 的映射关系。
- DataNode:响应读请求,传输 Block 数据。
2. 详细流程(6 步)
-
Client 发起读请求,NN 返回元数据
Client 通过DistributedFileSystem
向 NN 发送读文件请求(如hdfs dfs -get /hdfs/path localpath
),NN 校验:- Client 是否有文件读取权限;
- 目标文件是否存在。
校验通过后,NN 返回文件元数据: - 所有 Block 列表(如
Block1, Block2, ..., BlockN
); - 每个 Block 的所有副本所在 DN 列表(如
Block1: [DN1, DN2, DN3]
)。
-
Client 选择最优 DN
Client 按数据本地化原则选择每个 Block 的读取节点,优先级如下:- 优先 Client 所在节点的 DN(本地读取,无网络传输);
- 其次同机架的 DN(减少跨机架网络开销);
- 最后其他机架的 DN(仅当同机架无副本时)。
例:Client 在 NodeA,Block1 副本在 NodeA(DN1)、NodeB(DN2),则优先读 DN1。
-
Client 与 DN 建立连接并读取 Block
Client 与选定的 DN 建立 TCP 连接,发送“读取指定 Block”的请求。DN 从本地磁盘读取 Block 数据,传输给 Client。
Client 接收数据时同步验证 Checksum:- 校验通过:确认数据完整;
- 校验失败:放弃该 DN,选择同一 Block 的其他副本(如 DN2)重新读取。
-
Client 拼接 Block 为完整文件
Client 按 Block 顺序(Block1→Block2→...→BlockN
)读取所有 Block,暂存到本地缓冲区,最终拼接为完整文件,写入本地磁盘(如localpath
)。 -
容错处理:读取失败切换副本
若读取中 DN 故障(如网络中断),Client 立即中断连接:- 从该 Block 的其他副本 DN 重新读取;
- 记录故障 DN,后续读取其他 Block 时避开(直至其恢复)。
-
读取完成,关闭连接
所有 Block 读取并拼接完成后,Client 关闭与所有 DN 的连接,返回“读取成功”。
3. 关键优化机制
- 数据本地化:减少跨节点/跨机架网络传输,符合 Hadoop“移动计算而非数据”的设计理念,是 HDFS 读效率高的核心原因。
- 并行读取:Client 可同时向多个 DN 发起请求,并行读取不同 Block(如 Block1 读 DN1,Block2 读 DN4),缩短大文件总读取时间。
五、HDFS 元数据管理:fsimage、edits、seen_txid
NN 管理的元数据(目录结构、Block 映射等)是 HDFS 的核心,通过 fsimage
、edits
、seen_txid
三个文件确保元数据的一致性和持久性。
1. 三个核心文件的作用与特点
文件 | 作用 | 特点 |
---|---|---|
fsimage(文件系统镜像) | 存储某一时刻 HDFS 的完整元数据快照,包括目录/文件 inode 信息(权限、所有者、修改时间)、文件与 Block 映射、Block 副本位置等。 | 静态文件,不实时更新;体积大,加载速度快,NN 启动时优先加载以恢复基础元数据。 |
edits(编辑日志) | 记录 fsimage 快照之后的所有元数据变更操作(如创建文件、删除目录、修改权限、新增 Block 等)。 | 动态追加日志,每次变更立即写入,确保操作不丢失;需与 fsimage 配合使用以恢复最新元数据。 |
seen_txid(事务 ID 记录) | 记录 NN 最后一次处理的 edits 日志的事务 ID(txid),标识元数据变更进度。 | 简单文本文件,内容仅为一个数字(如 1000);用于故障恢复时定位需重放的 edits 范围(从 seen_txid+1 开始)。 |
2. 三者协同关系
- 正常运行:fsimage 保存历史快照,edits 实时记录新操作,seen_txid 跟踪最新 txid。
- Checkpoint(检查点)机制:Secondary NameNode 定期(默认 1 小时或 edits 达到 100 万次操作)合并 fsimage 和 edits:
- 2NN 向 NN 请求“停止写入 edits,生成新的 edits.inprogress”;
- 2NN 下载 NN 的 fsimage 和 edits;
- 2NN 合并两者,生成新的 fsimage(
fsimage.ckpt
); - 2NN 将新 fsimage 上传给 NN,NN 替换旧 fsimage,清空旧 edits,将
edits.inprogress
重命名为 edits; - seen_txid 更新为最新 txid,完成合并。
该机制避免 edits 文件过大导致 NN 启动时重放时间过长。
六、DataNode 可靠存储与故障处理(心跳汇报和块汇报)
DataNode 是 HDFS 的“存储载体”,其工作机制围绕“数据可靠存储”和“故障自动处理”展开。
1. 数据块存储
DataNode 存储 Block 时,会同时保存以下信息:
- 数据本身:Block 的二进制数据,存储在磁盘指定目录。
- 数据长度:记录 Block 的实际大小(避免读取不完整)。
- 校验和:与 Block 对应的 Checksum,存储在
.blk_xxx.crc
文件中。 - 时间戳:记录 Block 的创建/修改时间,用于版本管理。
2. 与 NameNode 的通信
- 心跳汇报(Heartbeat):DN 每 3 秒向 NN 发送一次心跳,包含自身状态(存活状态、磁盘使用率、Block 数量等)。若 NN 超过 10 分钟(默认)未收到心跳,判定 DN 宕机,触发副本修复。
- 块汇报(Block Report):DN 启动时或每隔 6 小时,向 NN 完整汇报自身存储的所有 Block 列表。NN 通过块汇报更新元数据(确保 Block 位置信息准确)。
3. 容错与数据可靠性保障
- 数据块损坏检测:Client 读取 Block 时验证 Checksum(校验和),若不匹配(数据损坏),立即向 NN 报告。NN 标记该 Block 为“损坏”,指令其他 DN 复制健康副本到新节点,同时删除损坏 Block。
- 节点故障处理:DN 宕机后,NN 检测到心跳超时,立即检查该 DN 上的所有 Block:
- 对副本数不足的 Block(如原 3 副本,宕机后剩 2 个),NN 调度其他 DN 复制副本,直至满足
dfs.replication
配置(默认 3 副本)。
- 对副本数不足的 Block(如原 3 副本,宕机后剩 2 个),NN 调度其他 DN 复制副本,直至满足
- 磁盘故障处理:DN 定期检查本地磁盘状态,若某磁盘故障,标记该磁盘上的所有 Block 为“丢失”,通过块汇报告知 NN,由 NN 触发副本修复。
七、常见面试题:为什么 HDFS 数据块大小不能太小或太大?
HDFS 默认 Block 大小为 128MB(Hadoop 2.x+),其大小设置需平衡“元数据开销”“IO 效率”和“并行度”,过小或过大都会导致问题。
1. 数据块太小的问题
- 元数据管理开销过大:NN 需存储每个 Block 的元数据,若 Block 太小(如 1KB),1GB 文件会拆分为 100 万个 Block,NN 内存需维护 100 万个元数据。PB 级集群下,元数据量会耗尽 NN 内存,甚至导致 NN 崩溃。
- 计算任务调度效率低:MapReduce 等框架按 Block 划分 Map 任务(1 个 Block 对应 1 个 Map 任务)。Block 太小会产生大量 Map 任务,每个任务的启动、初始化、资源分配(如 JVM 创建)有额外开销,YARN 调度成本剧增,整体计算效率下降。
- 磁盘寻道时间占比过高:磁盘读写包含“寻道时间”(磁头移动到数据位置,约毫秒级)和“传输时间”(数据读取到内存)。Block 太小会导致寻道时间占比远高于传输时间(如读 1KB 和 128MB Block 的寻道时间相同,但传输时间差异极大),磁盘 IO 效率低下。
2. 数据块太大的问题
- 数据传输耗时过长:若 Block 太大(如 1GB),单次传输需更长时间。若传输中发生网络波动或 DN 故障,重试需重新传输整个 Block,重试成本极高,影响数据可靠性和任务进度。
- 计算并行度不足:分布式计算的核心是“并行处理”,Block 太大导致 Map 任务数量过少。