Hadoop 架构概述
理解 Hadoop 的整体架构设计是学习 Hadoop 的第一步。本章将深入讲解 Hadoop 三大核心组件的架构原理和协作方式。
Hadoop 整体架构
Hadoop 采用主从架构(Master-Slave),整体架构可以分为三层:
架构分层说明
存储层(HDFS):最底层,负责数据的分布式存储。所有数据最终都存储在 HDFS 上,为上层计算提供数据支持。
资源调度层(YARN):中间层,负责集群资源的统一管理和调度。它接收上层应用的资源请求,将资源分配给应用使用。
应用层:最上层,运行各种计算框架和应用程序。MapReduce、Spark、Hive 等都运行在这一层。
HDFS 架构详解
HDFS(Hadoop Distributed File System)是 Hadoop 的分布式文件存储系统,采用主从架构设计。
核心组件
NameNode(名称节点)
NameNode 是 HDFS 的主节点,整个集群只有一个活跃的 NameNode(高可用模式下可以有多个),负责管理文件系统的元数据。
主要职责:
-
管理文件系统命名空间:维护整个文件系统的目录树结构,包括文件名、目录结构、文件属性等。
-
管理数据块映射信息:记录每个文件由哪些数据块组成,每个数据块存储在哪些 DataNode 上。
-
处理客户端请求:响应客户端的文件读写请求,返回数据块位置信息。
-
管理 DataNode:接收 DataNode 的心跳和块报告,监控 DataNode 的健康状态。
元数据管理:
NameNode 的元数据主要存储在内存中,同时持久化到磁盘:
| 文件 | 说明 |
|---|---|
| FsImage | 文件系统命名空间的完整快照,包含所有文件和目录的元数据 |
| EditLog | 记录对文件系统的所有修改操作,用于恢复和更新 FsImage |
元数据的工作流程:
- 客户端发起写操作请求
- NameNode 先将操作记录到 EditLog
- 更新内存中的元数据
- 返回成功响应给客户端
DataNode(数据节点)
DataNode 是 HDFS 的工作节点,集群中可以有多个 DataNode,负责实际的数据存储。
主要职责:
-
存储数据块:将文件切分成固定大小的块(默认 128MB)存储在本地文件系统。
-
响应读写请求:处理客户端的数据读写请求,返回或接收数据。
-
心跳汇报:定期向 NameNode 发送心跳信号,表明自己存活。
-
块报告:定期向 NameNode 发送块报告,汇报自己存储的所有数据块信息。
数据块存储:
DataNode 将数据块存储在本地文件系统的指定目录下:
${dfs.datanode.data.dir}/
├── current/
│ ├── BP-1234567890-1.2.3.4-1234567890123/
│ │ ├── current/
│ │ │ ├── finalized/
│ │ │ │ ├── subdir0/
│ │ │ │ │ ├── blk_1073741825
│ │ │ │ │ ├── blk_1073741825_1001.meta
│ │ │ │ │ ├── blk_1073741826
│ │ │ │ │ └── blk_1073741826_1002.meta
其中 blk_* 文件存储实际数据,blk_*.meta 文件存储校验和信息。
Secondary NameNode
Secondary NameNode 不是 NameNode 的热备节点,它的主要作用是辅助 NameNode 进行元数据合并。
主要职责:
-
定期合并 FsImage 和 EditLog:减轻 NameNode 的负担,防止 EditLog 过大。
-
创建检查点:生成新的 FsImage 文件,加快 NameNode 启动速度。
-
提供元数据备份:合并后的 FsImage 可以用于 NameNode 恢复。
合并流程:
HDFS 文件读写流程
文件读取流程
客户端读取 HDFS 文件的完整流程:
详细步骤说明:
-
打开文件:客户端调用
FileSystem.open()方法打开文件,请求发送到 NameNode。 -
获取块位置:NameNode 返回文件的数据块列表,每个块包含存储该块的 DataNode 地址列表(按距离排序)。
-
建立连接:客户端选择最近的 DataNode 建立连接,开始读取数据。
-
读取数据:DataNode 将数据流式传输给客户端。
-
继续读取:当前块读取完成后,客户端连接下一个块的 DataNode 继续读取。
-
关闭连接:所有数据读取完成后,客户端关闭连接。
文件写入流程
客户端写入 HDFS 文件的完整流程:
详细步骤说明:
-
创建文件:客户端调用
FileSystem.create()方法创建文件,NameNode 检查权限并创建文件元数据。 -
获取 DataNode 列表:NameNode 根据副本放置策略,返回可写入的 DataNode 列表。
-
建立管道:客户端与 DataNode 建立管道连接,数据将依次流经各个 DataNode。
-
写入数据:客户端将数据分成数据包,依次发送到管道中的 DataNode。
-
确认写入:所有副本写入完成后,最后一个 DataNode 返回确认,依次向前传递。
-
关闭文件:数据写入完成后,客户端调用
close()方法关闭文件,NameNode 更新文件元数据。
数据块与副本机制
数据块(Block)
HDFS 将文件切分成固定大小的块进行存储:
| 配置项 | 默认值 | 说明 |
|---|---|---|
dfs.blocksize | 128MB | Hadoop 2.x/3.x 默认块大小 |
dfs.blocksize | 64MB | Hadoop 1.x 默认块大小 |
为什么使用大数据块?
-
减少元数据占用:块越大,NameNode 需要管理的块数量越少,内存占用越低。
-
减少寻址时间:大块可以减少客户端与 NameNode 的交互次数。
-
提高传输效率:大块可以更有效地利用网络带宽。
块大小如何选择?
- 数据量小、文件数量多:可以适当减小块大小
- 数据量大、文件数量少:可以适当增大块大小
- 一般建议:块大小设置为磁盘传输时间的 1-2 倍
副本机制
HDFS 通过多副本机制保证数据可靠性:
| 配置项 | 默认值 | 说明 |
|---|---|---|
dfs.replication | 3 | 默认副本数 |
副本放置策略:
副本的放置位置直接影响数据可靠性和读写性能:
-
第一个副本:优先放在客户端所在节点;如果客户端不在集群内,则随机选择一个节点。
-
第二个副本:放在与第一个副本不同机架的节点上,保证机架级别的容错。
-
第三个副本:放在第二个副本同机架的不同节点上,平衡网络开销和可靠性。
这种放置策略的优势:
- 高可靠性:一个机架故障不会丢失数据
- 高效读取:可以从最近的副本读取数据
- 均衡负载:写入时利用多个机架的网络带宽
MapReduce 架构详解
MapReduce 是 Hadoop 的分布式计算框架,采用分而治之的思想处理大规模数据。
编程模型
MapReduce 将复杂的分布式计算抽象为两个阶段:
Map 阶段
Map 阶段负责数据的映射和初步处理:
- 输入:键值对
(K1, V1) - 处理:用户定义的 Map 函数对每个输入进行处理
- 输出:中间结果
(K2, V2)
Reduce 阶段
Reduce 阶段负责数据的汇总和最终处理:
- 输入:分组后的中间结果
(K2, List<V2>) - 处理:用户定义的 Reduce 函数对每组数据进行汇总
- 输出:最终结果
(K3, V3)
执行流程
MapReduce 作业的完整执行流程:
详细步骤:
-
输入分片:将输入文件按大小切分成多个分片(Split),每个分片启动一个 Map 任务处理。
-
Map 执行:Map 任务读取分片数据,执行用户定义的 Map 函数,输出中间结果。
-
Shuffle 过程:
- Partition:根据 Key 的哈希值将数据分配到不同的 Reduce 任务
- Sort:对每个分区内的数据按 Key 排序
- Combine:可选的本地合并,减少网络传输
- Group:相同 Key 的数据分组
-
Reduce 执行:Reduce 任务拉取属于自己的数据,执行用户定义的 Reduce 函数。
-
输出结果:Reduce 输出结果写入 HDFS。
核心组件
JobTracker(Hadoop 1.x)
在 Hadoop 1.x 中,JobTracker 负责作业调度和任务管理:
- 接收客户端提交的作业
- 将作业分解为 Map 和 Reduce 任务
- 将任务分配给 TaskTracker 执行
- 监控任务执行状态,处理失败重试
缺点:JobTracker 是单点故障,且资源管理和任务调度耦合,扩展性差。
TaskTracker(Hadoop 1.x)
TaskTracker 运行在每个节点上:
- 执行 JobTracker 分配的任务
- 向 JobTracker 汇报任务状态和资源使用情况
- 管理本地资源槽位(Map Slot 和 Reduce Slot)
MRAppMaster(Hadoop 2.x/3.x)
在 Hadoop 2.x 及以后版本,MRAppMaster 替代了 JobTracker 的部分功能:
- 每个作业有一个独立的 MRAppMaster
- 负责作业的初始化、任务调度、状态监控
- 向 YARN 申请资源,与 NodeManager 协作执行任务
YARN 架构详解
YARN(Yet Another Resource Negotiator)是 Hadoop 2.x 引入的资源管理系统,实现了资源管理与任务调度的分离。
核心组件
ResourceManager
ResourceManager 是 YARN 的主节点,负责整个集群的资源管理:
主要职责:
-
资源调度:根据调度策略将资源分配给各个应用程序。
-
应用管理:接收应用程序提交,启动 ApplicationMaster。
-
状态监控:监控集群资源使用情况和 NodeManager 状态。
内部组件:
| 组件 | 功能 |
|---|---|
| Scheduler | 纯粹的资源调度器,负责资源分配 |
| ApplicationsManager | 管理应用程序的提交和 ApplicationMaster 的启动 |
NodeManager
NodeManager 运行在每个节点上,负责单个节点的资源管理:
主要职责:
-
资源汇报:定期向 ResourceManager 汇报节点的资源使用情况。
-
容器管理:启动、监控、停止容器。
-
资源隔离:保证容器之间的资源隔离(CPU、内存等)。
-
健康检查:监控节点健康状态,上报异常。
内部组件:
| 组件 | 功能 |
|---|---|
| ContainerExecutor | 执行容器的启动和停止命令 |
| NodeStatusUpdater | 向 ResourceManager 汇报节点状态 |
| ContainerManager | 管理容器生命周期 |
| ResourceLocalizationService | 本地化资源文件 |
ApplicationMaster
ApplicationMaster 是每个应用程序的管理者:
主要职责:
-
任务切分:将应用程序切分成多个任务。
-
资源申请:向 ResourceManager 申请执行任务所需的资源。
-
任务调度:在分配的容器上调度任务执行。
-
状态监控:监控任务执行状态,处理失败重试。
-
容错处理:任务失败时申请新资源重新执行。
Container
Container 是 YARN 中资源的抽象单位,封装了:
- CPU:虚拟 CPU 核心数(vcores)
- 内存:可用内存大小(MB)
- 其他资源:GPU、磁盘等(可选)
YARN 工作流程
应用程序在 YARN 上的执行流程:
详细步骤说明:
-
提交应用:客户端向 ResourceManager 提交应用程序,包括 ApplicationMaster 程序、启动命令、资源需求等。
-
分配 Container:ResourceManager 选择一个 NodeManager,为其分配一个 Container 用于启动 ApplicationMaster。
-
启动 ApplicationMaster:NodeManager 在分配的 Container 中启动 ApplicationMaster。
-
注册并申请资源:ApplicationMaster 向 ResourceManager 注册,并申请执行任务所需的资源。
-
返回 Container 列表:ResourceManager 根据调度策略返回可用的 Container 列表。
-
启动任务 Container:ApplicationMaster 与 NodeManager 通信,在 Container 中启动任务。
-
执行任务:任务在 Container 中执行,处理数据。
-
汇报状态:NodeManager 向 ApplicationMaster 汇报任务执行状态。
-
注销应用:应用执行完成后,ApplicationMaster 向 ResourceManager 注销,释放资源。
小结
本章介绍了 Hadoop 的整体架构设计:
-
HDFS:分布式文件系统,采用 NameNode/DataNode 主从架构,通过数据块和副本机制实现可靠存储。
-
MapReduce:分布式计算框架,采用 Map/Reduce 两阶段编程模型,通过 Shuffle 机制实现数据分发和排序。
-
YARN:资源管理系统,采用 ResourceManager/NodeManager/ApplicationMaster 架构,实现资源与计算的解耦。
理解这些架构设计对于后续学习 Hadoop 的安装配置、程序开发和性能调优非常重要。