全部版块 我的主页
论坛 数据科学与人工智能 大数据分析 Hadoop论坛
26 0
2025-11-22

一、实验常用命令详解

(一)环境配置与基础操作

  • 使环境变量生效:执行 source /etc/profile 命令,确保系统读取最新的环境配置。
  • 解压压缩包:使用 tar -zxvf 包名 -C 解压路径 进行解压。例如:tar -zxvf hadoop-3.1.3.tar.gz -C /opt/module/,将Hadoop安装包解压至指定目录。
  • 验证JDK是否正常:运行 java -version 查看Java版本信息,确认JDK已正确安装。
  • 检查Hadoop安装状态:输入 hadoop version 显示Hadoop版本,测试其可用性。
  • SSH远程连接服务器:通过 ssh [用户名]@[目标IP] 登录远程主机,如:ssh user@192.168.1.100;完成操作后输入 exit 退出会话。
  • 查看Java进程:执行 jps 可列出当前所有正在运行的Java程序,常用于判断Hadoop服务是否启动成功。
  • 删除目录及内容:使用 rm -rf 文件夹名称 强制递归删除指定文件夹及其内部所有数据,请谨慎操作。
  • 分发文件到其他节点:调用自定义脚本 xsync 文件名 实现跨机器同步,例如:xsync /root/myhadoop.sh,适用于集群环境下的配置传播。

(二)Hadoop集群典型操作流程

1. 启动Hadoop集群

# 进入Hadoop安装目录
cd /home/hadoop/hadoop-3.1.3

# 启动全部Hadoop服务
./sbin/start-all.sh

# 检查各守护进程是否运行
jps
[此处为图片1]

2. 在本地创建用于测试的数据文件

# 新建存储目录
mkdir /home/hadoop/files
cd /home/hadoop/files

# 创建并写入文本内容
echo "Hello Hadoop Hello MapReduce" > file.txt

3. 将本地文件上传至HDFS分布式文件系统

# 切换到Hadoop主目录
cd /home/hadoop/hadoop-3.1.3

# 在HDFS中创建输入目录结构
./bin/hdfs dfs -mkdir /input
./bin/hdfs dfs -mkdir /input/wordcount

# 上传本地file.txt到HDFS指定路径
./bin/hdfs dfs -put /home/hadoop/files/file.txt /input/wordcount/

# 验证上传结果
./bin/hdfs dfs -ls /input/wordcount

4. 执行MapReduce任务(以WordCount为例)

# 提交MapReduce示例作业进行词频统计
./bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /input/wordcount /output/wordcount

# 输出计算结果
./bin/hdfs dfs -cat /output/wordcount/part-r-00000
[此处为图片2]

二、核心配置文件解析

(一)常见考题与配置文件对应关系

问题描述 选项 正确答案 解析说明
JAVA_HOME应在哪个配置文件中设置? A. hadoop-default.xml
B. hadoop-env.sh
C. hadoop-site.xml
D. configuration.xsl
B hadoop-env.sh用于设定Hadoop运行所需的环境变量;
hadoop-default.xml为默认配置不可修改;
hadoop-site.xml曾用于覆盖默认值;
configuration.xsl仅用于XML页面格式化展示。
fs.default.name参数应配置在哪个文件? A. mapred-site.xml
B. core-site.xml
C. hdfs-site.xml
D. 以上均不是
B core-site.xml是核心配置文件,负责定义HDFS访问地址和默认工作目录等关键属性;
mapred-site.xml管理MapReduce框架参数;
hdfs-site.xml则控制副本数量和块大小等HDFS行为。
Hadoop 0.20版本中,hadoop-site.xml拆分后的文件不包括哪一个? A. conf-site.xml
B. mapred-site.xml
C. core-site.xml
D. hdfs-site.xml
A 从Hadoop 0.20开始,原hadoop-site.xml被拆分为三个独立文件:
core-site.xmlhdfs-site.xmlmapred-site.xml,不再包含conf-site.xml
完全分布式模式下需要修改的主要配置文件有哪些? core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml

(二)主要配置文件功能说明

  • hadoop-env.sh:设置Hadoop运行依赖的环境变量,如必须配置的JAVA_HOME
  • hadoop-default.xml:系统内置的默认配置文件,通常不应直接编辑。
  • hadoop-site.xml:旧版中用户自定义配置文件,用于覆盖默认设置,在新版本中已被细分替代。
  • core-site.xml:核心全局配置文件,包含HDFS访问入口(fs.default.name)、临时目录等基础设定。
  • hdfs-site.xml:专门用于配置HDFS相关参数,如副本因子(replication factor)、数据块大小(block size)等。
  • mapred-site.xml:定义MapReduce计算框架的行为,包括JobTracker地址、任务调度方式等。
  • yarn-site.xml:YARN资源管理系统的核心配置文件,涉及ResourceManager、NodeManager等组件的设置。

三、各章节核心知识点

(一)第一章 大数据时代

1. 大数据(Big Data)定义:指在一定时间范围内无法通过传统软件工具进行有效捕捉、管理与处理的数据集合。这类数据需借助新型处理模式,以实现更强的决策支持、深度洞察和流程优化能力,具有海量性、高增长速率及多样化的特征,属于一种重要的信息资产。

2. 大数据的5V特征:

  • Volume(大量):数据的采集、存储与计算规模巨大。
  • Variety(多样):数据来源广泛,类型丰富,涵盖结构化与非结构化数据。
  • Value(低价值密度):单条数据价值较低,需通过深度挖掘才能以低成本创造高价值。
  • Veracity(真实):强调数据的真实性与准确性,保障整体数据质量。
  • Velocity(高速):数据生成、获取和处理速度快,对实时性要求高。

3. Hadoop 相关知识:

  • 创始人:Doug Cutting,同时也是 Nutch 和 Lucene 的创建者(Solr 并非由其创立)。
  • 本质:一个由多个软件库构成的框架,适用于大规模数据处理,具备高吞吐量特性。
  • 核心设计:HDFS 负责数据存储,MapReduce 负责分布式计算。
  • 物理架构:采用 Master-Slave 架构模式。
  • 部署方式:运行于集群环境,具备高容错性,可在廉价硬件上部署。
  • 主要特性:
    1. 可在低成本硬件上部署,提供可靠、高效且可扩展的大数据处理能力。
    2. 具备高可靠性,能够按位级别进行数据存储与处理。
    3. 高效性体现在节点间动态迁移数据,维持系统负载均衡。
    4. 高拓展性,集群规模可轻松扩展至数千个节点。
    5. 高容错机制,自动保存多份数据副本,并在任务失败时重新分配执行。

4. Hadoop 生态系统组成:

  • Hadoop 1.x 核心组件:HDFS(用于海量数据存储)与 MapReduce(实现分布式计算)。
  • Hadoop 2.x 核心升级:在原有基础上引入 YARN,负责资源管理与任务调度。
  • 其他关键组件包括:
    1. Hive:构建于 Hadoop 之上的数据仓库工具,支持使用类 SQL 查询语言 HiveQL 进行离线数据分析
    2. HBase:分布式、面向列的开源数据库,适合处理非结构化数据。
    3. ZooKeeper:提供分布式协调服务,用于配置维护、命名服务等功能。
    4. Mahout:基于 Hadoop 的机器学习库,集成多种经典算法实现。
    5. Oozie:工作流调度引擎,用于管理和协调相互依赖的周期性任务。

(二)第二章 Hadoop3.x 环境搭建

1. HDFS 集群角色(基于 Master/Slave 架构):

  • NameNode(主节点)功能:
    1. 管理数据块的映射关系。
    2. 响应客户端的读写请求。
    3. 设定数据副本策略。
    4. 维护 HDFS 的命名空间。
    5. 存储文件系统的元数据,如文件名、数据块位置等信息。
  • Secondary NameNode 作用:
    1. 辅助 NameNode 工作,作为冷备份存在。
    2. 定期合并 fsimage 与 edits 日志文件,并将结果发送回 NameNode。
    3. 通过周期性合并 EditLog 和 FsImage,减轻主节点的运行压力。
  • DataNode(从节点)职责:
    1. 存储客户端上传的数据块 Block。
    2. 执行实际的数据块读取与写入操作。
    3. 定时向 NameNode 发送心跳信号及块报告,确保状态同步。

[此处为图片1]

2. YARN 核心组件(Hadoop 2.x 及以上版本):

  • ResourceManager:负责整个集群中计算资源的统一调度与分配。
  • NodeManager:运行在各个节点上,负责启动并监控计算容器,同时上报资源使用情况。
  • MRAppMaster:专用于协调 MapReduce 作业的任务执行过程。

3. 其他重要角色(Hadoop 2.x+ 支持的高可用配置):

  • Standby NameNode:作为 Active NameNode 的热备节点,支持故障自动切换。
  • JournalNode(HA 模式下):用于持久化存储 NameNode 的状态信息,允许多个 NameNode 共享同一状态数据。
  • ZooKeeper(HA 模式下):参与 ResourceManager 和 NameNode 的主节点选举,保障系统的高可用性。
  • HDFS Client:提供访问 HDFS 的客户端接口,支持文件的读写操作。
  • YARN Client:用于提交 MapReduce 作业及其他分布式计算任务到集群。

4. Hadoop 的三种运行模式:

  • 独立(本地)模式:不启动任何守护进程,所有程序运行在同一 JVM 中,适用于 MapReduce 程序的开发与测试阶段。
  • 伪分布式模式:所有 Hadoop 守护进程运行在单台机器上,模拟小型集群环境,便于学习与调试。
  • 全分布式模式:守护进程分布在多个物理节点上,主节点与从节点分离,构成真正的生产级集群环境。

[此处为图片2]

5. 模式相关考题:

题目 选项 答案 解析

关于Hadoop运行模式的正确描述

在Hadoop的不同运行模式中,单机模式与伪分布式模式存在明显区别。单机模式不启动任何守护进程,主要用于调试和测试MapReduce程序,且不使用HDFS文件系统;而伪分布式模式则会在同一台机器上模拟完整的Hadoop集群环境,包括NameNode、DataNode、ResourceManager、NodeManager等守护进程,并启用HDFS进行数据存储与读写操作。

因此,以下说法中:

  • A选项错误:单机模式并不起动任何守护进程;
  • B选项错误:单机模式既不使用HDFS,也不加载任何守护进程;
  • C选项错误:伪分布式模式需要与各个守护进程交互以实现功能;
  • D选项正确:伪分布式模式相较于单机模式,增加了HDFS输入输出支持,并可监控内存使用情况。

Hadoop的运行模式分类

Hadoop共有三种标准运行模式:

  1. 单机(本地)模式:默认模式,无须配置,所有服务运行在一个JVM进程中,不涉及HDFS或网络通信;
  2. 伪分布式模式:在一台机器上运行所有Hadoop守护进程,各组件通过不同线程模拟分布环境;
  3. 全分布式模式:多个节点组成真实集群,NameNode、DataNode、ResourceManager等部署在不同主机上。

因此,“互联网模式”并非Hadoop的运行模式之一,属于干扰项。

Hadoop集群搭建与常用操作命令

以下是Hadoop集群初始化及日常管理中的基本命令集合:

  • 格式化NameNode:bin/hdfs namenode -format
  • 启动整个集群:sbin/start-all.sh(也可分别执行 sbin/start-dfs.sh 和 sbin/start-yarn.sh)
  • 停止集群服务:sbin/stop-all.sh
  • 查看HDFS目录内容:hdfs dfs -ls /user/software
  • 显示文件内容:hadoop fs -cat /user/tmp/data.txt
  • 上传本地文件至HDFS:hadoop fs -put /home/t/file.txt /user/t
  • 上传本地目录至HDFS:hadoop fs -put /home/t/dir_name /user/t
  • 从HDFS下载文件到本地:hadoop fs -get /user/t/ok.txt /home/t
  • 删除HDFS上的文件:hadoop fs -rm /user/t/ok.txt
  • 递归删除HDFS目录:hdfs dfs -rm -r /user/t
  • 创建HDFS目录:hadoop fs -mkdir /user/t
  • 创建空文件:hadoop fs -touchz /user/new.txt
  • 重命名或移动文件:hadoop fs -mv /user/test.txt /user/ok.txt
  • 合并HDFS目录下所有文件并下载:hadoop fs -getmerge /user /home/t
  • 终止指定作业:hadoop job -kill [job-id]

说明:hadoop fs 与 hdfs dfs 命令功能一致,可互换使用。

第三章:认识HDFS分布式文件系统

1. HDFS简介

HDFS是Google GFS的开源实现,采用Master/Slave架构设计,专为大规模数据集的分布式存储而构建,为MapReduce计算框架提供底层数据支撑。与其类似的系统还包括GFS本身,在考试中可能作为参考答案出现。

2. HDFS的主要特性

  • 适用于大数据处理:Hadoop 2.x及以上版本默认Block大小为128MB,可通过配置文件 hdfs-site.xml 中的 dfs.block.size 参数调整;文件按块切分存储,未满整块的小文件不会占用全部空间。
  • 流式数据访问:遵循“一次写入,多次读取”的原则,这是其最高效的访问方式。
  • 基于商用硬件运行:可在普通服务器集群上部署,默认保存3个副本,具备自动检测与恢复丢失副本的能力。
  • 高容错性与良好扩展性:支持横向扩展,具有较强的配置灵活性。
  • 跨平台兼容:由Java编写,可在任意支持JVM的平台上运行。
  • Shell接口支持:提供丰富的命令行工具用于文件系统管理。
  • 内置Web管理界面:NameNode与DataNode自带Web服务器,便于实时查看集群状态。
  • 权限控制机制:采用类似POSIX的权限模型,包含用户、组和其他三类访问权限。
  • 机架感知能力:根据物理拓扑优化任务调度与数据存放位置。
  • 安全模式:集群启动时自动进入,用于验证数据块完整性。
  • Rebalancer功能:自动均衡各DataNode之间的数据负载。
  • 支持软件升级与回滚:当更新失败时,可恢复至之前的稳定版本。

3. HDFS的设计目标

  • 首要目标为快速检测并应对硬件故障;
  • 优先保障高吞吐量的数据访问,而非低延迟响应;
  • 支持海量大文件的高效存储;
  • 采用简化的一致性模型——仅允许追加或写一次,读多次;
  • 强调“移动计算比移动数据更经济”,即计算尽量靠近数据所在节点;
  • 具备良好的可移植性,方便在多种环境中部署;
  • 确保系统出错时仍能维持数据可靠性;
  • 通信协议基于TCP/IP,客户端通过TCP端口连接NameNode进行交互。

4. HDFS中的Block机制

HDFS将大文件分割成固定大小的数据块进行存储:

  • 默认Block大小为128MB(Hadoop 2.x+),早期版本为64MB;
  • 增大Block尺寸是为了降低寻址开销,使数据传输时间远大于定位时间;
  • 举例说明:对于100MB数据,若寻址耗时10ms,传输速率为100MB/s,则:
    • 使用100MB Block时,寻址时间占比约1%;
    • 使用10MB Block时,该比例上升至10%。
  • 优势包括:允许文件大小超过单个磁盘容量;简化存储管理;有利于副本复制与容错处理。

5. 数据复制机制

HDFS通过多副本机制保障数据可靠性:

  • 副本因子(Replication Factor)在文件创建时由客户端设定,默认值为3;
  • 副本存放策略遵循特定规则,综合考虑节点健康状况、机架分布等因素,提升容灾能力和网络效率。

1. 第一个副本存储位置的选择逻辑:若客户端位于集群内部,则优先选择其所在机架中的节点作为第一个副本存放点;若客户端不在集群内,则从集群中随机选取一个节点,但会避开负载过高或资源紧张的节点。

2. 第二个副本的放置策略:选择与第一个副本所在机架不同的另一个机架上的任意节点,实现跨机架冗余。

3. 第三个副本的位置确定:在第二个副本所在的机架中,选择一个不同于第二个副本的节点进行存储。

- 设计目的:通过跨机架分布副本,减少机架之间的数据传输频率,提升写入效率;同时保障系统容错能力——当某个机架发生故障时,仍可通过其他机架获取数据副本,确保服务可用性。

[此处为图片1]

6. 机架感知机制

  • 启用方式:在 NameNode 的 core-site.xml 配置文件中设置参数 net.topology.script.file.name,指定一个脚本路径。该脚本接收 DataNode 的网络地址作为输入,输出对应的机架 ID(RackID)。
  • 未启用状态:所有节点默认归属于 /default-rack,副本选择完全随机。
  • 启用后的副本选择规则
    1. 如果上传文件的客户端本身是 DataNode,则将其作为第一个写入节点;否则,从 Slave 节点中随机选择一个。
    2. 第二个节点选定为第一个节点所在机架之外的另一机架上的随机节点。
    3. 第三个节点位于第二个节点所属机架内的不同节点上;若前两个副本已在不同机架,则第三个副本与第二个同机架。
    4. NameNode 根据客户端与各 DataNode 之间的网络“距离”进行排序,优先选择距离较近的节点。
    5. DFSClient 按照距离由近及远的顺序依次向节点写入数据块。

7. 安全模式详解

  • 定义:安全模式是 Hadoop 集群的一种保护性运行状态。NameNode 在启动过程中会自动进入此模式,也可通过命令手动触发。
  • 主要功能:用于检查 HDFS 中所有数据块的完整性与副本状态。
  • 退出条件:当系统中已报告的数据块副本比例达到设定阈值(默认为 0.999,配置项为 dfs.safemode.threshold.pct,位于 hdfs-default.xml 文件中),NameNode 将自动退出安全模式。
  • 操作限制:在安全模式下,不允许对命名空间进行修改(如创建、删除文件),也不允许执行数据块的复制或删除操作;但用户仍可浏览目录结构和查看文件内容。
  • 常用管理命令
    • 进入安全模式:hadoop dfsadmin -safemode enter
    • 退出安全模式:hadoop dfsadmin -safemode leave
    • 查看当前状态:hadoop dfsadmin -safemode get
    • 等待直至退出:hadoop dfsadmin -safemode wait
[此处为图片2]

考题示例:

题目 选项 答案 解析
NameNode启动时进入安全模式,说法错误的是? A. 检查DataNode数据块有效性
B. 必要时复制/删除数据块
C. 满足最小副本比率条件时自动退出
D. 文件系统允许修改
D 安全模式下禁止对文件系统进行任何修改操作,包括创建、删除或重命名文件等。

8. 负载均衡机制

  • 执行命令HADOOP_HOME/bin/start-balancer.sh -t 10%,其中 -t 参数表示磁盘使用率偏差阈值,当各节点间使用率差异低于该值时,认为集群已达到平衡状态。
  • 处理流程
    1. NameNode 接收来自各个 DataNode 的存储报告;
    2. 分析并获取部分数据块的映射信息;
    3. 启动数据块复制过程;
    4. 在目标节点完成复制后替换原有块;
    5. 确认复制成功;
    6. 最终确认旧块被正确替换。

9. 心跳机制工作机制

  • 基本概念:心跳是指集群中节点之间按照固定频率发送请求与响应消息,以维持通信连接和状态同步。
  • 具体实现方式
    1. Master 节点启动后开启 RPC Server,等待 Slave 节点建立心跳连接。
    2. Slave 节点启动后主动连接 Master,并每隔 3 秒发送一次心跳信号(间隔时间可通过 heartbeat.recheck.interval 参数调整)。
    3. Slave 在心跳中上报自身运行状态,Master 可借此下发控制指令。
    4. 整个集群内部进程间的通信均依赖于基于 RPC 的心跳机制完成。
    5. 若 NameNode 在一定时间内未收到某 DataNode 的心跳,将该节点标记为“dead node”,并立即启动数据恢复流程,将其负责的数据块副本复制到其他正常运行的 DataNode 上。
[此处为图片3]

10. HDFS 集群架构概述

  • 典型结构:采用单 NameNode 架构,包含一个 NameNode 和多个 DataNode。
  • NameNode 角色:作为中心服务器,负责管理文件系统的命名空间,处理客户端访问请求,执行诸如打开、关闭、重命名等文件系统操作,并决定数据块(Block)与 DataNode 之间的映射关系。
  • DataNode 角色:响应客户端的读写请求,在 NameNode 的调度下完成数据块的创建、删除和复制任务。

11. 核心组件详细说明

NameNode(名称节点 / 元数据节点)

  • 作为集群的核心管理者,集群中仅存在一个活动的 NameNode 实例。
  • 核心职责
    • 提供名称查询服务(通常集成 Jetty 服务器);
    • 持久化保存元数据信息,包括文件所有者、权限设置、文件到数据块的映射关系、以及数据块到 DataNode 的映射表;
    • 系统启动时将元数据加载至内存,以提高访问效率。
  • 元数据存储形式:在磁盘上分为两类文件——操作日志(edits)和命名空间镜像(fsimage)。两者共同构成完整的元数据备份。(考题答案:两者都是)
  • 高可用保障:通过 HA(High Availability)机制实现故障切换与容灾。

SecondaryNameNode

  • 常见误解澄清:它并非 NameNode 的热备节点。(考题答案:错误)
  • 实际作用
    • 定期合并 edits 日志和 fsimage 镜像文件;
    • 清空过大的 edits 文件,生成新的 fsimage 并上传回 NameNode;
    • 有效缩短 NameNode 的重启时间,提升系统稳定性与完整性。
  • 合并流程步骤
    1. NameNode 创建一个新的空日志文件 edits.new,开始记录后续操作;
    2. SecondaryNameNode 从 NameNode 下载当前的 fsimage 和 edits 文件;
    3. 在本地完成合并,生成临时镜像 fsimage.ckpt;
    4. 将合并后的 fsimage.ckpt 传回 NameNode;
    5. NameNode 使用新镜像替换原有的 fsimage 和 edits 文件。

4. 触发条件与DataNode功能解析

HDFS中的检查点操作由core-site.xml配置文件中的两个参数控制:fs.checkpoint.period(默认值为3600秒)和fs.checkpoint.size(默认大小为67108864字节)。当满足任一条件时,Secondary NameNode将协助NameNode执行元数据的合并与持久化。

DataNode作为HDFS的数据存储节点,主要承担以下职责:

  1. 负责实际数据块(Block)的存储,每个Block都对应一个元数据文件,用于记录其所属文件、块序号等信息。
  2. 具备核心运行机制:启动阶段主动向NameNode上报所持有的Block列表;通过周期性心跳维持与NameNode的通信连接(若连续10分钟未发送心跳,则被视为失效节点);并执行数据块的读取、写入、复制及删除等操作。

常见考题示例:在HDFS架构中,负责具体数据存储的是哪个组件?答案为:DataNode。[此处为图片1]

(四)第四章 HDFS运行机制详解

RPC通信机制

远程过程调用(RPC)是Hadoop分布式系统中实现进程间通信的核心协议,基于TCP/IP或UDP进行数据传输。Hadoop自研的RPC框架包含以下几个关键层次:

  1. 序列化层:采用Hadoop内置的序列化机制,支持Writable接口的类进行高效序列化,也可使用自定义Writable类型提升性能。
  2. 函数调用层:借助Java动态代理与反射技术,实现客户端对远程服务方法的透明调用。
  3. 网络传输层:基于标准Socket机制构建,确保跨节点之间的可靠数据交换。
  4. 服务器端框架层:利用Java NIO结合事件驱动I/O模型,显著增强服务端的并发处理能力。

HDFS文件写入流程(详细说明)

文件写入过程涉及客户端、NameNode与多个DataNode之间的协同工作,具体步骤如下:

  1. 客户端通过DistributedFileSystem向NameNode发起“创建文件”请求。
  2. NameNode验证用户权限、目标路径是否存在,并确认可写后记录相应元数据,返回允许创建响应。
  3. 客户端初始化FSDataOutputStream输出流对象。
  4. 将待写入文件切分为多个数据包(packet),并通过流式方式发送至首个DataNode;该节点再依次将数据转发给后续DataNode,形成一条管道式传输链路(即DataNode Pipeline),以完成副本冗余存储。
  5. 每成功接收一个数据包,各DataNode向上游节点回传确认包(ack packet),确保传输可靠性。
  6. 全部数据传输完毕后,客户端调用FSDataOutputStream.close()方法关闭输出流。
  7. 客户端通知NameNode写入已完成,NameNode更新文件状态为“持久化完成”。

另一种角度描述该流程:

  1. 客户端请求上传文件,NameNode校验父目录存在性、文件是否已存在以及客户端写权限。
  2. 根据校验结果返回是否允许上传。
  3. 客户端请求第一个Block的目标存储节点列表。
  4. NameNode返回三个推荐的DataNode(如dn1、dn2、dn3)。
  5. 客户端通过FSDataOutputStream连接dn1开始上传,dn1建立到dn2的连接,dn2再连通dn3,形成三级管道。
  6. dn3→dn2→dn1逐级返回应答信号,确认通道建立成功。
  7. 客户端以Packet为单位向dn1发送第一个Block的数据,dn1转发至dn2,dn2再转至dn3;同时dn1将每个Packet加入等待ACK队列。
  8. 当前Block传输完成后,客户端再次向NameNode申请下一个Block的存储位置,重复上述流程直至全部写入完成。

写入过程示例:

  • 假设block1大小为64MB,按64KB划分为多个package。
  • 客户端将第一个package发送至Rack1上的host2。
  • host2接收后立即转发给Rack2的host1,同时客户端继续向host2发送第二个package。
  • host1接收到数据后转发至同机架的host3,与此同时host2向host1发送第二个package。
  • 此流水线模式持续进行,直到整个block1传输结束。
  • 最终host2、host1、host3共同向NameNode报告完成状态,NameNode确认后通知host2,再由host2告知客户端。
  • 客户端向NameNode发送最终确认,标志block1写入成功。

典型问题:HDFS中是谁负责将文件分割成多个Block?答案:Client。[此处为图片2]

HDFS文件读取流程

读取操作同样依赖NameNode与DataNode的协作,具体流程如下:

  1. 客户端通过DistributedFileSystem向NameNode提交“打开文件”请求。
  2. NameNode返回该文件所有Block的位置信息(包括各Block所在的DataNode地址)。
  3. 客户端初始化FSDataInputStream输入流。
  4. 选择距离最近的DataNode(通常依据网络拓扑结构)开始读取第一个数据块。
  5. 若文件包含多个Block,则继续读取下一个Block,优先选取地理位置或网络延迟最优的DataNode。
  6. 所有数据读取完成后,调用FSDataInputStream.close()关闭流。

HDFS一致性模型

定义:指文件在读写过程中数据可见性的规则,保证客户端能正确感知文件内容的变化。

存在的问题:

  • 新建文件后立即可以被发现,但初始内容可能不可见(表现为文件长度为0)。
  • 当写入超过一个Block时,第一个Block对新开启的读取者可见,而正在写入的当前Block仍处于不可见状态。

解决方案:调用sync()方法强制刷新缓冲区,该方法返回后,所有已写入的数据对新的读者均可见;此外,关闭文件流时会隐式执行sync()操作。

代码示例:

Path p = new Path("home/temp/a.txt");
FSDataOutputStream out = fs.create(p);
out.write("content".getBytes("UTF-8"));
out.hsync();

注:hsync()确保数据被刷写到操作系统缓冲区,提供更强的持久性保障。[此处为图片3]

5. HDFS HA机制(Hadoop2.x及以上版本)

HDFS高可用性(HA)机制通过配置“活动-备用”模式的NameNode来实现系统容错。当Active NameNode发生故障时,Standby NameNode可自动接管服务,确保集群持续运行。

核心组件包括:

  1. Active NameNode:负责对外提供读写服务,处理客户端请求。
  2. Standby NameNode:实时同步Active NameNode的元数据变更(如EditLog),在主节点失效时迅速升级为主节点。
  3. ZKFailoverController(ZKFC):独立运行的进程,监控NameNode状态并主导主备切换流程。
  4. ZooKeeper集群:协助完成主备选举,保证同一时刻仅有一个Active节点。
  5. 共享存储系统:作为元数据共享通道,供主备NameNode访问一致的命名空间信息。
  6. DataNode:同时向Active和Standby NameNode上报数据块位置与状态信息,保障元数据同步完整性。

优势特点:

  • 扩展性与隔离性增强:支持多个NameNode横向扩展namespace,不同用户或应用可使用独立命名空间,提升资源隔离能力。
  • 通用化存储支持:通过Block Pool抽象层,允许非HDFS文件系统及HBase等应用直接利用底层存储架构。
  • 架构简洁且兼容性强:主要修改集中在DataNode、配置模块和工具集,原有NameNode设计保持稳定,具备良好的向后兼容性。

存在的局限性:

  • 单点故障风险依然存在:若未配置Secondary NameNode,一旦某个NameNode宕机,其所管理的数据将暂时无法访问。
  • 负载均衡需手动干预:当前不支持自动负载分摊,需通过Client Side Mount Table等机制进行人工配置以实现流量分配。
[此处为图片1]

第五章 访问HDFS系统

1. 命令行方式访问

可通过以下两种命令前缀操作HDFS:

  • hadoop fs ...
  • hdfs dfs ...

注:hadoop dfs ...为旧版语法,仍保留兼容性支持。

常用操作示例:

  • 上传本地文件
    hadoop fs -copyFromLocal input/docs/quangle.txt hdfs://localhost/user/tom/quangle.txt
    可省略完整URL写法:
    hadoop fs -copyFromLocal input/docs/quangle.txt /user/tom/quangle.txt
  • 下载文件到本地
    hadoop fs -copyToLocal quangle.txt quangle.copy.txt
  • 验证文件完整性
    md5sum input/docs/quangle.txt quangle.copy.txt
  • 创建目录并上传文件
    hadoop fs -mkdir /gl
    hadoop fs -put sample.txt /
    hadoop fs -ls /

核心命令功能汇总表:

命令 功能说明 典型应用场景示例
hadoop dfs -ls 列出指定路径下的文件或目录内容 查看HDFS根目录内容:
hadoop dfs -ls /
hadoop dfs -lsr 递归列出目录及其子目录中的所有内容 -
hadoop dfs -df 显示目录磁盘使用情况 -
hadoop dfs -du 展示目录内各文件与子目录的大小 -
hadoop dfs -count [-q] 统计目录下文件数量与子目录数;添加-q参数可查看配额信息 -
hadoop dfs -mv 在HDFS内部移动文件或目录 -
hadoop dfs -rm [-skipTrash] 将文件移至回收站;使用-skipTrash则直接删除 -
hadoop dfs -rmr [-skipTrash] 递归删除目录及其内容(默认进入回收站) 清空考试目录:
hadoop dfs -rmr /exam
hadoop dfs -expunge 彻底清空回收站中已删除的文件 -
hadoop dfs -put 将本地文件上传至HDFS指定路径 上传测试文件:
hadoop dfs -put /home/test.txt /input
hadoop dfs -get [-ignoreCrc] [-crc] 从HDFS下载文件至本地;可选是否校验CRC 下载结果文件:
hadoop dfs -get /output/result.txt /home
hadoop dfs -copyToLocal [-ignoreCrc] [-crc] 功能与get类似,用于将HDFS文件复制到本地 -
hadoop dfs -moveToLocal [-crc] 将HDFS文件移动到本地(原文件被删除);支持CRC信息迁移 -
hadoop dfs -mkdir 在HDFS上创建新目录 创建考试专用目录:
hadoop dfs -mkdir /exam
hadoop dfs -touchz 在HDFS上生成一个0字节的空文件 生成测试空文件:
hadoop dfs -touchz /exam/test.txt
hadoop dfs -text 输出HDFS中文本文件的内容(自动解压缩) -
[此处为图片2]
hadoop dfs -cat 用于查看HDFS中文件的内容。例如,可通过命令查看存储在HDFS上的配置文件内容:
hadoop dfs -cat /config/hadoop-site.xml

hadoop dfs -setrep [-R][-w] 可设置指定文件或目录的副本数量,其中-R表示递归应用到所有子文件。例如,将/test目录下所有文件的副本数设为2:
hadoop dfs -setrep -R 2 /test

hadoop dfs -test -[ezd] 用于对文件进行条件判断:-e检测文件是否存在,-z判断文件是否为空(0字节),-d判断是否为目录。例如,检查/exam路径是否为目录:
hadoop dfs -test -d /exam

hadoop dfs -stat [format] 用于输出文件或目录的统计信息,支持格式化参数,如%b表示文件大小,%n表示文件名等。

hadoop dfs -chmod [-R] 用于修改文件或目录的权限,使用-R可递归更改。例如,将/test.txt文件权限修改为755:
hadoop dfs -chmod 755 /test.txt

hadoop dfs -chown [-R] [OWNER][:[GROUP]] 用于更改文件或目录的所有者(及所属组),-R表示递归操作。例如,将/test目录及其内容的所有者更改为user:
hadoop dfs -chown -R user /test

hadoop dfs -chgrp [-R] GROUP 用于修改文件或目录的所属组,-R为递归执行。例如,将/test.txt文件的所属组更改为group1:
hadoop dfs -chgrp group1 /test.txt

hadoop dfs -help 显示所有可用的HDFS命令帮助信息。

hadoop dfs -copyFromLocal 功能与put命令类似,用于将本地文件复制到HDFS中。

hadoop dfs -moveFromLocal 将本地文件移动至HDFS指定路径,移动后本地源文件将被删除。
[此处为图片1]

2. Java API 访问方式:

要通过Java程序访问HDFS,客户端必须具备以下条件:
- 包含 hdfs-site.xml 配置文件,以便获取NameNode的相关连接信息;
- 引用 $HADOOP_HOME/lib 目录下的必要JAR包以支持Hadoop运行时环境。

Hadoop提供了一个抽象类 org.apache.hadoop.fs.FileSystem,作为不同文件系统的统一接口。以下是常见的文件系统实现及其对应URL方案和说明:

| 文件系统 | URL方案 | Java实现类 | 说明 |
|----------|--------|------------|------|
| Local file | file | fs.LocalFileSystem | 带校验功能的本地磁盘文件系统 |
| HDFS | hdfs | hdfs.DistributedFileSystem | Hadoop分布式文件系统核心实现 |
| Hftp | hftp | hdfs.HftpFileSystem | 支持通过HTTP协议对HDFS进行只读访问 |
| HSFTP | hsftp | hdfs.HsftpFileSystem | 基于HTTPS协议的HDFS只读访问 |
| WebHDFS | webhdfs | hdfs.web.WebHdfsFileSystem | 提供基于HTTP的安全读写访问能力 |
| HAR | har | fs.HarFileSystem | 构建于其他文件系统之上,用于归档文件 |
| kfs | kfs | fs.kfs.KosmosFileSystem | CloudStore文件系统(类似GFS),由C++编写 |
| FTP | ftp | fs.ftp.FTPFileSystem | 由远程FTP服务器支撑的文件系统 |
| S3(原生) | s3n | fs.s3native.NativeS3FileSystem | 由Amazon S3对象存储支持的文件系统 |

[此处为图片2]

API 使用示例:

1. 使用URL方式从HDFS读取数据:
该方法需注册自定义的流处理器工厂FsUrlStreamHandlerFactory,从而支持hdfs://等协议。

java
import org.apache.hadoop.fs.FsUrlStreamHandlerFactory;
import org.apache.hadoop.io.IOUtils;
import java.io.InputStream;
import java.net.URL;

public class URLCat {
    static {
        URL.setURLStreamHandlerFactory(new FsUrlStreamHandlerFactory());
    }

    public static void main(String[] args) throws Exception {
        InputStream in = null;
        try {
            in = new URL(args[0]).openStream();
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}

2. 利用FileSystem API读取HDFS文件:
通过Configuration和FileSystem类直接构建连接,实现更灵活的操作控制。

java
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.Configuration;

以下代码展示了如何在HDFS上进行基础的目录创建操作:

import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;

public class CreateDirectory {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/output/newdir";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path mkdirPath = new Path(uri);
        boolean isCreated = fs.mkdirs(mkdirPath);
        System.out.println(isCreated ? "目录创建成功" : "目录创建失败");
    }
}
[此处为图片1]

接下来是将本地文件上传至HDFS的实现方式。该程序通过输入流读取本地文件,并将其写入分布式文件系统中,同时在传输过程中显示进度提示符“.”。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.Progressable;
import org.apache.hadoop.io.IOUtils;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URI;

public class FileCopyFromLocal {
    public static void main(String[] args) throws Exception {
        String localSrc = "/home/hadoop/files/sample.txt";
        String dst = "hdfs://master:9000/input/hadoop/sample.txt";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(dst), conf);
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(localSrc));
            out = fs.create(new Path(dst), new Progressable() {
                @Override
                public void progress() {
                    System.out.print(".");
                }
            });
            IOUtils.copyBytes(in, out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
            IOUtils.closeStream(out);
        }
    }
}
[此处为图片2]

从HDFS中删除指定文件的操作也十分常见。下面的代码示例演示了如何删除一个已存在的HDFS文件,并输出操作结果状态。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;

public class DeleteFile {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input/hadoop/sample.txt";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path deletePath = new Path(uri);
        boolean isDeleted = fs.delete(deletePath, false);
        System.out.println(isDeleted ? "删除成功" : "删除失败");
    }
}
[此处为图片3]

最后是一个读取HDFS文件内容并输出到控制台的Java程序。它利用FileSystem的open方法获取文件输入流,并通过IOUtils工具类将数据复制到标准输出。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import java.io.InputStream;
import java.net.URI;

public class FileSystemCat {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input/sample.txt";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        InputStream in = null;
        try {
            in = fs.open(new Path(uri));
            IOUtils.copyBytes(in, System.out, 4096, false);
        } finally {
            IOUtils.closeStream(in);
        }
    }
}
[此处为图片4]
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;
public class CreateDir {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input/hadoop/tmp";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path dirPath = new Path(uri);
        boolean isCreated = fs.mkdirs(dirPath);
        System.out.println(isCreated ? "目录创建成功" : "目录创建失败");
    }
}

上述代码用于在HDFS中创建指定路径的目录。通过调用fs.mkdirs()方法实现目录的递归创建,并输出操作结果状态。

[此处为图片1]
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;

public class CheckFileIsExist {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input/hadoop/sample.txt";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path path = new Path(uri);
        boolean isExists = fs.exists(path);
        System.out.println(isExists ? "文件存在" : "文件不存在");
    }
}

该程序段的功能是判断HDFS中某个指定路径的文件是否存在。利用FileSystem对象的exists()方法返回布尔值,进而打印出“文件存在”或“文件不存在”的提示信息。

[此处为图片2]
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;

public class ListFiles {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path path = new Path(uri);
        FileStatus[] status = fs.listStatus(path);
        for (FileStatus s : status) {
            System.out.println(s.getPath().toString());
        }
        fs.close();
    }
}

此代码示例展示了如何列出HDFS中某一目录下的所有子文件和子目录。通过调用listStatus()方法获取文件状态数组,遍历并输出每个条目的完整路径。最后关闭文件系统连接以释放资源。

[此处为图片3]
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockLocation;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import java.net.URI;

public class LocationFile {
    public static void main(String[] args) throws Exception {
        String uri = "hdfs://master:9000/input/sample.txt";
        Configuration conf = new Configuration();
        FileSystem fs = FileSystem.get(URI.create(uri), conf);
        Path path = new Path(uri);

该部分代码用于后续获取HDFS文件的数据块存储位置信息。初始化了文件系统的连接以及目标文件的路径对象,为下一步读取块信息做准备。

[此处为图片4]
FileStatus status = fs.getFileStatus(path);
BlockLocation[] blocks = fs.getFileBlockLocations(status, 0, status.getLen());
for (int i = 0; i < blocks.length; i++) {
    String[] hosts = blocks[i].getHosts();
    System.out.println("block_" + i + "_location: " + hosts[0]);
}
fs.close();

API相关考题

题目 选项 答案 解析
下列关于Hadoop API的说法错误的是? A. Hadoop的文件API不是通用的,只用于HDFS文件系统
B. Configuration类的默认实例化方法是以HDFS系统的资源配置为基础的
C. FileStatus对象存储文件和目录的元数据
D. FSDataInputStream是java.io.DataInputStream的子类
A A错误:Hadoop文件API具有通用性,不仅支持HDFS,还支持本地文件系统、S3等多种存储系统;B正确:Configuration类默认加载HDFS相关的配置文件进行初始化;C正确:FileStatus用于封装文件或目录的元信息,如路径、长度、权限等;D正确:FSDataInputStream继承自java.io.DataInputStream,扩展了对HDFS随机读取的支持

其他访问方式

  • ThriftFS:通过Apache Thrift服务将Hadoop文件系统进行封装,允许任何支持Thrift绑定的语言(如Python、C++、Ruby等)与HDFS进行交互操作,提升跨语言兼容性。
[此处为图片1]

第六章 Hadoop IO优化

1. 数据完整性保障机制

Hadoop通过校验和机制确保数据在传输和存储过程中的完整性。

校验方式:采用循环冗余校验(CRC),每个文件对应生成一个以.crc为后缀的校验文件,例如.passwd.crc检测机制:
  1. 当DataNode接收到客户端写入的数据时,会同时保存原始数据块及其对应的校验和。在写操作过程中,客户端将数据和校验和沿管道依次发送至各DataNode,最后一个节点负责验证校验和是否匹配,若不一致则抛出ChecksumException异常。
  2. 客户端从DataNode读取数据时,会重新计算所接收数据的校验和,并与服务器端存储的校验值进行比对。DataNode自身也会维护校验和日志,记录每个数据块最近一次被验证的时间戳。
  3. DataNode后台运行DataBlockScanner进程,定期扫描并验证其管理的所有数据块,主动发现潜在损坏。
损坏处理流程:
  1. 客户端在读取某个数据块时发现校验失败,立即向NameNode报告该Block的损坏情况以及涉及的DataNode地址,并抛出ChecksumException
  2. NameNode接收到报告后,将该副本标记为“已损坏”,不再将其分配给新的读请求,也不会参与后续的数据复制任务。
  3. 为维持设定的副本数量(replication factor),NameNode会调度其他正常节点上的完整副本进行重新复制,填补缺失。
  4. 待新副本建立成功后,NameNode指示相应DataNode删除原始损坏的数据块。

2. 文件压缩策略

合理使用压缩技术可有效降低存储开销,并加快数据在磁盘和网络间的传输效率。

优势:
  • 减少磁盘占用空间
  • 提升I/O吞吐能力,尤其在网络带宽受限场景下效果显著
使用建议:
  • 计算密集型任务:尽量避免使用高压缩率算法,防止CPU成为瓶颈
  • I/O密集型任务:推荐启用压缩,缓解读写压力
常见压缩格式对比:
压缩格式 压缩率 压缩速度 Split支持 应用场景
gzip 适用于压缩后小于130MB的文件(单HDFS块内),如小时级或天级日志归档;Hive、MapReduce、Streaming程序无需代码调整即可支持
lzo 适合大于200MB的大文件压缩,文件越大优势越明显;支持分片处理,可用于直接作为MapReduce输入
snappy 常用于MapReduce作业中map阶段输出的中间结果压缩;也可作为某一作业输出供下一作业输入,兼顾性能与效率
bzip2 适用于对压缩率要求高而对速度无严格限制的场景;可用于长期存档类MapReduce输出;支持Split特性,兼容部分遗留应用中的大文本处理需求
压缩性能排序:
  • 按压缩率从高到低:bzip2 > gzip > lzo ≈ snappy
  • 按压缩速度从快到慢:snappy > lzo > gzip > bzip2

3. 文件序列化机制

序列化是分布式系统中实现数据跨节点传递的核心技术之一。

定义:将内存中的结构化对象转换为字节流的过程称为序列化;反之,从字节流重建对象的过程称为反序列化。 目的:支持高效的远程过程调用(RPC),确保数据传输的安全性、高效性和紧凑性。 设计要求:
  • 紧凑性:尽可能减小序列化后的数据体积,节省存储与带宽资源
  • 高性能:序列化/反序列化过程应快速,减少额外处理开销
  • 可扩展性:能够在不破坏旧版本兼容性的前提下支持新增字段
  • 互操作性:支持多种编程语言对持久化数据的读写操作
核心接口:
  • Writable:用于值类型的序列化,提供基本的读写功能
  • WritableComparable<T>:扩展自Writable,同时实现Comparable接口,主要用于键类型,支持排序操作
常用实现类:
  • 布尔型:BooleanWritable
  • 整数型:ByteWritableShortWritableIntWritableVIntWritableLongWritableVLongWritable
  • 浮点型:FloatWritableDoubleWritable
  • 字符串类型:Text(UTF-8编码,替代Java原生String)

(七)第七章 MapReduce编程模型

1. 核心概念

MapReduce采用“分而治之”的编程思想,将大规模数据处理任务分解为多个可并行执行的子任务,最终汇总结果。整个过程以键值对(Key-Value)作为基本的数据表示形式。

其核心流程如下:

(k1, v1) → Map → list(k2, v2) → Shuffle(分组与合并) → (k2, list(v2)) → Reduce → list(k3, v3)

其中,Combine函数是可选组件,形式上与Reduce函数一致,作用是在Map端进行局部聚合,减少网络传输的数据量,提升整体性能。

2. 优势特点

  • 开发简便:用户只需实现Map和Reduce两个逻辑模块,无需关心底层的分布式计算、进程通信等复杂机制。
  • 良好的可扩展性:通过增加集群节点即可线性扩展处理能力。
  • 高容错性:当某个节点发生故障时,系统会自动将任务重新调度到其他正常节点继续执行。
  • 适用于大规模离线批处理:特别适合PB级以上数据的批量分析场景。

3. 存在的局限性

  • 执行效率较低:主要瓶颈在于磁盘IO操作频繁,中间结果需多次写入磁盘并通过网络传输。
  • 编程接口较底层:对非工程背景的数据分析师不够友好,通常需要借助Hive等高层工具辅助使用。
  • 算法支持有限:并非所有算法都适用于该模型,尤其不支持依赖状态共享或参数迭代的复杂算法(如部分机器学习训练过程)。

4. 关键执行流程详解

Map阶段:接收输入的键值对(k1, v1),经过处理后输出中间结果(k2, v2)。

Shuffle阶段:

Map端操作流程:

  1. 每个输入分片对应一个Map任务,默认分片大小等于HDFS块大小(例如128MB)。
  2. Map输出首先写入内存中的环形缓冲区,当达到设定阈值时开始溢写至磁盘。
  3. 在溢写前,数据会根据Reduce任务数量进行分区,每个分区内按键进行排序(采用快速排序算法)。
  4. Map任务结束前,将所有溢写的临时文件合并成一个有序且按分区组织的最终文件(使用归并排序)。
  5. 生成的分区数据会被拷贝发送给对应的Reduce任务节点。
[此处为图片1]

Reduce端操作流程:

  1. 从各个Map任务接收属于本Reduce的有序数据片段。
  2. 将这些来自不同Map的溢写文件再次进行归并排序,形成一个更大的有序文件。
  3. 最后一次合并的结果直接传递给Reduce函数处理,避免额外的磁盘读写。
  4. 针对排序后的每一个唯一键,调用一次Reduce函数进行聚合计算。

排序机制说明:

  • 共经历三次排序:第一次为Map端内存中缓冲区数据的快速排序;第二次为Map端多个溢写文件合并时的归并排序;第三次为Reduce端整合所有Map输出时的归并排序。
  • 排序算法选择:内存排序使用快速排序,文件间合并则采用归并排序以保证稳定性和效率。

5. 编程相关常见问题解析

题目 选项 答案 解析
Hadoop集群的主要瓶颈是? A. CPU B. 磁盘IO C. 网络 D. 内存 B MapReduce属于IO密集型作业,大量中间结果需读写磁盘并经网络传输,因此磁盘IO成为主要性能瓶颈。
下列关于MapReduce说法不正确的是? A. MapReduce是一种计算框架 B. MapReduce来源于google的学术论文 C. MapReduce程序只能用java语言编写 D. MapReduce隐藏了并行计算的细节,方便使用 C MapReduce支持多语言开发,例如可通过Hadoop Streaming使用Python、Shell等脚本语言编写Mapper和Reducer。
MapReduce框架中,支持序列化的类充当键或值,以下说法错误的是? A. 实现Writable接口的类是值 B. 实现WritableComparable接口的类可以是值或键 C. Hadoop的基本类型Text并不实现WritableComparable接口 D. 键和值的数据类型可以超出Hadoop自身支持的基本类型 C Text类实际上实现了WritableComparable接口,因此既可以作为值也可以作为键使用。
在MapReduce编程模型中,键必须实现下列哪个接口? A. WritableComparable B. Comparable C. Writable D. LongWritable A 由于键需要参与排序,因此必须实现WritableComparable接口;而值仅需实现Writable接口即可。
Hadoop Streaming未设定Reducer时,运行会出现问题吗? A. 会 B. 不会 B 若未显式指定Reducer,默认会启用IdentityReducer,直接输出接收到的键值对,不会导致运行失败。
YARN的基本思想是将Hadoop中哪个进程拆分为ResourceManager和ApplicationMaster? A. JobTracker B. TaskTracker C. NameNode D. DataNode A YARN将原Hadoop 1.x中的JobTracker职责拆分为两部分:资源管理由ResourceManager负责,任务调度由ApplicationMaster承担。

此外,在实际应用中还涉及多种支持序列化的集合类,包括但不限于:
ArrayWritable、ArrayPrimitiveWritable、TwoDArrayWritable、MapWritable、SortedMapWritable、EnumMapWritable。
这些类用于封装复杂结构的数据,便于在MapReduce各阶段之间高效传输。

6. Hadoop Streaming 示例

执行命令如下:

bin/hadoop jar contrib/streaming/hadoop-0.20-streaming.jar -input input/filename -output output -mapper 'dosth.py 5' -file dosth.py -D mapred.reduce.tasks=1

说明:

  • 利用 Unix 流机制实现程序与 Hadoop 的交互。
  • 支持任意可执行的脚本语言处理数据流,具备良好的扩展性。
  • 所使用的脚本需遵循 UNIX 标准输入(STDIN)和标准输出(STDOUT)规范。
  • 若未显式指定 Reducer,默认采用 IdentityReducer 进行处理。
[此处为图片1]

(八)第八章 基于 YARN 的运行机制解析

YARN 的诞生背景:为满足对 HDFS 上数据进行大规模交互式处理的需求而设计,旨在提升集群资源利用率与作业调度效率。

核心设计理念:将原 JobTracker 的双重职责——资源管理与任务调度/监控——进行解耦。资源管理交由全局的 ResourceManager 负责,而每个应用程序的调度与协调则由其专属的 ApplicationMaster 承担。

主要组件构成:

  • ResourceManager(RM):负责整个系统的资源监控、分配与管理,具有最高控制权限。
  • NodeManager(NM):部署在各个计算节点上,负责本地资源维护、容器启动与监控,并定期向 RM 汇报资源使用情况。
  • ApplicationMaster(AM):每个应用实例对应一个 AM,负责该应用的任务调度,向 RM 申请资源,并与 NM 协作完成任务的执行与状态跟踪。

典型工作流程:

  1. 客户端向 ResourceManager 提交应用程序请求。
  2. ResourceManager 分配首个容器,并在其中启动对应的 ApplicationMaster。
  3. ApplicationMaster 向 ResourceManager 动态申请所需计算资源。
  4. 获得资源后,AM 与相应 NodeManager 协商,在容器中启动具体任务并监控其运行状态。
  5. 任务执行完毕或应用结束时,ApplicationMaster 向 ResourceManager 注销自身,释放所有占用资源。

(九)第九章 MapReduce 高级特性(仅考察 Join 联接)

1. Reduce Side Join(Reduce 端连接)

基本原理:

  • Map 阶段:同时读取两个输入文件(File1 和 File2),为每条记录添加来源标签(例如 tag=1 表示来自 File1,tag=2 表示来自 File2)。
  • Reduce 阶段:接收具有相同 key 的所有 value 列表(包含来自两个文件的数据),通过笛卡尔积方式完成连接操作。

产生原因:由于 Map 阶段无法获取完整的 join 字段信息,且同 key 的数据可能分布在不同的 Map 任务中,因此必须推迟到 Reduce 阶段进行合并处理。

特点分析:实现逻辑简单,适用于任意大小的表连接;但缺点在于 Shuffle 阶段传输数据量大,网络 IO 开销高,整体性能较低。

2. Map Side Join(Map 端连接)

核心思想:将较小的数据表复制多份,分发至各节点并在每个 Map 任务的内存中构建哈希表(如 HashMap)。随后在扫描大表的过程中,以记录的 key 查询哈希表,若匹配成功则直接输出连接结果。

适用场景:适用于“一大一小”两张表之间的连接操作。

优势:连接操作在 Map 阶段即完成,避免了中间数据写入 Shuffle 过程,显著减少网络传输开销,执行效率较高。

局限性:不适用于两个均为大表的情况,受限于单个 Map 任务的内存容量。

3. SemiJoin(半连接)

实现思路:首先提取小表中的 join 键集合,通过 DistributedCache 将其广播到各个计算节点,并加载进内存(如 HashSet 结构)。在 Map 阶段处理大表时,先判断当前记录的 join 键是否存在于本地缓存中,若不存在则过滤掉,仅保留可参与连接的有效记录。

这些筛选后的记录仍需经过 Shuffle 传输至 Reduce 端,后续连接流程与 Reduce Side Join 相同。

优化目的:有效减少 Shuffle 阶段的数据传输量,缓解网络 IO 瓶颈,是对传统 Reduce Side Join 的重要改进手段。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群