Apache Hadoop HDFS 架构

FreeGuideOnline 最新 2026-07-13

HDFS 概述

HDFS(Hadoop Distributed File System)是 Apache Hadoop 生态的核心存储组件,专为运行在廉价硬件集群上的大规模数据存储而设计。它以高容错、高吞吐量访问和流式数据处理为核心目标,是分布式计算框架(如 MapReduce、Spark)的理想基石。

设计理念

  • 超大文件:HDFS 擅长处理 GB 级甚至 TB 级的单个文件,而非海量小文件。
  • 一次写入,多次读取:数据写入后很少需要修改,这简化了数据一致性模型并提高了吞吐。
  • 流式数据访问:关注高吞吐量而非低延迟,适合批量处理而非交互式查询。
  • 硬件故障是常态:通过多副本策略自动处理节点故障,保障数据不丢失。
  • 移动计算比移动数据更划算:优先将计算任务调度到数据所在的节点,降低网络开销。

HDFS 核心架构

HDFS 采用主/从(Master/Slave)架构,由一个 NameNode(主节点)和多个 DataNode(从节点)组成。

                   ┌──────────┐
                   │  Client  │
                   └─────┬────┘
              ┌──────────┴──────────┐
              │                     │
         ┌────▼─────┐          ┌────▼─────┐
         │ NameNode │          │Secondary │
         │  (主节点) │          │NameNode  │(检查点节点)
         └────┬─────┘          └──────────┘
   ┌──────────┼──────────┐
   │          │          │
┌──▼──┐   ┌──▼──┐   ┌──▼──┐
│Data │   │Data │   │Data │
│Node1│   │Node2│   │Node3│
└─────┘   └─────┘   └─────┘

NameNode(名称节点)

NameNode 是 HDFS 的管理者,负责:

  • 元数据管理:维护整个文件系统的目录树,记录每个文件的名称、目录结构、文件到数据块的映射关系等。
  • 数据块位置信息:掌握每个数据块存储在哪些 DataNode 上(该信息不持久化,由 DataNode 启动时上报)。
  • 命名空间操作:处理客户端的文件创建、打开、关闭、重命名等请求。
  • 副本策略控制:监控数据块副本数量,当副本数不足或增加时,触发复制或删除。

注意:NameNode 将所有元数据保存在内存中以保证高性能,因此其内存大小决定了集群能存储的文件数量上限。在生产中,NameNode 通常会部署在内存充裕的节点上。

DataNode(数据节点)

DataNode 是实际存储数据的节点,负责:

  • 数据块的读写:根据 NameNode 的指令完成数据块的存储或读取。
  • 心跳汇报:定期(默认 3 秒)向 NameNode 发送心跳,报告存活状态及持有的数据块列表。
  • 副本维护:根据 NameNode 的调度,执行数据块的复制、删除或转移任务。
  • 流水线复制:当客户端写入数据时,DataNode 之间以管道方式传输数据,依次写入多个副本。

Secondary NameNode(辅助名称节点)

尽管名字带“Secondary”,但它并不是 NameNode 的热备份,而是帮助 NameNode 合并编辑日志(EditLog)和镜像文件(FsImage)的检查点节点。

  • FsImage:某一时刻文件系统命名空间的完整快照。
  • EditLog:记录每次元数据变更的事务日志,如创建文件、删除文件等。
  • 随着运行,EditLog 会不断增长。Secondary NameNode 定期获取 NameNode 的 FsImage 和 EditLog,合并后生成新的 FsImage 回传给 NameNode,从而限制 EditLog 的大小,加速 NameNode 重启恢复。

在高可用(HA)配置中,该角色被备用 NameNode(Standby NameNode)取代。


数据块与副本机制

数据块化存储

HDFS 将文件拆分为固定大小的块(block)进行存储,默认块大小为 128 MB(Hadoop 2.x 及以后;1.x 默认为 64 MB)。拆分后每个块作为独立单元存储,文件可以大于集群中任意单个磁盘的容量。

  • 块大小可配置:可在 hdfs-site.xml 中通过 dfs.blocksize 参数调整,典型值从 128 MB 到 512 MB 不等。
  • 按块寻址:NameNode 记录每个文件由哪些块组成,客户端需通过 NameNode 获取块位置再直接与 DataNode 通信。

多副本策略

为提供高容错,每个数据块默认保存 3 份副本。副本放置策略兼顾可靠性和网络带宽:

  1. 第一个副本:若客户端位于 DataNode 上,则优先写入本地节点;否则随机选择一台 DataNode。
  2. 第二个副本:放置在与第一个副本 不同机架 的节点上,以应对机架级故障。
  3. 第三个副本:放置在与第二个副本 相同机架 但不同节点上,以减少跨机架传输开销。

当发现某个块的副本数不足时,NameNode 会指令 DataNode 从其余副本复制,以维持目标副本数。


HDFS 读写流程

写入文件流程

  1. 客户端调用 DistributedFileSystem.create() 并向 NameNode 发起 创建文件请求
  2. NameNode 检查命名空间(是否重名、权限等),通过后在元数据中创建文件记录,并返回 块分配信息(DataNode 列表) 给客户端。
  3. 客户端将数据切分成一个个数据包,通过 FSDataOutputStream 建立与第一个 DataNode 的 数据管道(Pipeline)
  4. 第一个 DataNode 连续接收数据包,一边写入本地磁盘,一边转发给第二个 DataNode,依此类推,直到所有副本节点都完成写入。
  5. 每个数据包写入完毕后,DataNode 沿管道反向发送确认(ACK)。
  6. 当第一个块写满后,客户端重复步骤 2 获取新块的 DataNode 列表,开始下一个块的写入。
  7. 文件所有块写入完成后,客户端调用 close(),并向 NameNode 发送完成信号。

读取文件流程

  1. 客户端通过 DistributedFileSystem.open() 打开文件,NameNode 返回文件 块列表及每个块所在的 DataNode 地址(按与客户端的距离排序)。
  2. 客户端从最近的 DataNode 开始读取第一个块的数据,FSDataInputStream 封装了具体通信。
  3. 当某个块的读取失败或网络中断,客户端自动尝试从下一个拥有该副本的 DataNode 继续读取。
  4. 读取完一个块后,切换到下一个块的地址,直到文件全部读取完毕。

整个读写过程中,客户端直接与 DataNode 交互,NameNode 仅提供元数据定位,这避免了单点瓶颈。


高可用性与容错

NameNode 单点故障的解决

早期 HDFS 中 NameNode 单点故障是整个集群的致命弱点。如今通过 HDFS High Availability(HA) 方案实现双 NameNode 热备:

  • 配置一对 Active NameNode 和 Standby NameNode。
  • 两个 NameNode 通过 共享存储(JournalNode 集群或共享 NAS) 同步编辑日志,Standby 节点实时回放 EditLog 保持内存元数据一致。
  • 所有 DataNode 同时向两个 NameNode 发送心跳和块报告。
  • 使用 ZooKeeper + FailoverController 自动检测故障并切换 Active 节点。

有了 HA 之后,Secondary NameNode 的职责被 Standby NameNode 替代 — Standby 负责定期合并 FsImage 并上传回 Active 节点,不再需要额外的 Secondary NameNode。

DataNode 容错

  • 副本自动恢复:当 DataNode 掉线或磁盘损坏导致块副本不足,NameNode 会安排其他节点补全副本。
  • 心跳超时:若默认 10 分钟内未收到心跳,NameNode 将该 DataNode 标记为“死亡”,不再向其分配新请求,并启动块副本补充。
  • 校验和检测:DataNode 存储数据时保存校验和,读取时自动校验,发现数据损坏则返回错误,客户端转而读取其他副本。

机架感知(Rack Awareness)

为了提高网络效率和数据可靠性,HDFS 支持将节点划分到逻辑机架。管理员可通过脚本或配置表定义每个 DataNode 所属的机架 ID。

  • 副本放置策略会考虑机架信息,确保至少一个副本位于不同机架。
  • 读取数据时,NameNode 根据机架距离排序返回的 DataNode 列表,使客户端优先访问同机架节点,降低带宽消耗。
  • 通过 net.topology.script.file.name 参数指定机架映射脚本,Hadoop 自动感知节点所属机架。

关键配置参数速览

参数 默认值 说明
dfs.blocksize 134217728 (128M) 数据块大小(字节)
dfs.replication 3 默认副本数
dfs.namenode.heartbeat.recheck-interval 300000 (5分钟) 判定 DataNode 死亡的时间
dfs.ha.automatic-failover.enabled false 是否开启自动故障转移
dfs.namenode.name.dir file://${hadoop.tmp.dir}/dfs/name NameNode 元数据存储路径
dfs.datanode.data.dir file://${hadoop.tmp.dir}/dfs/data DataNode 数据存储路径
dfs.namenode.secondary.http-address 0.0.0.0:9868 (取决于版本) Secondary NameNode 地址

适用场景与局限

擅长处理的场景

  • 超大规模数据集(PB 级)的存储与处理。
  • 对吞吐量要求极高的批量数据处理。
  • 一次写入、多次读取的日志分析、数据仓库等。
  • 需要良好横向扩展能力的廉价硬件集群。

不擅长的场景

  • 低延迟数据访问:HDFS 为高吞吐设计,不适合毫秒级访问。
  • 大量小文件:每个文件的元数据占用 NameNode 内存,小文件过多会耗尽内存并降低 RPC 性能。
  • 任意文件修改:不支持已有文件的随机写入和修改,仅支持追加(Hadoop 3.x 支持追加但性能有限)。

对于要求低延迟或海量小文件的场景,可以考虑 HBase、Apache Kudu 或对象存储(如 S3)等替代方案。


总结

HDFS 通过 NameNode/DataNode 主从架构、分块存储、多副本冗余和机架感知策略,构建了一个高度可靠、可线性扩展的分布式文件系统。掌握其架构原理和读写流程,是深入 Hadoop 生态及大规模数据处理的重要基础。在实际生产中,还需结合高可用部署、块大小调优及合理的命名空间设计,才能充分发挥其效能。