1. HDFS Shell 命令详解
HDFS Shell 命令是操作 Hadoop 分布式文件系统最基础、最常用的方式。它通过 hdfs dfs 或 hadoop fs 前缀调用,两者在大多数场景下等价。下面按功能分类介绍常用命令。
1.1 文件与目录操作
这类命令用于查看、创建、删除和移动 HDFS 中的文件与目录。
- 查看目录列表 :
hdfs dfs -ls /path,递归查看加-R参数。 - 创建目录 :
hdfs dfs -mkdir -p /user/hadoop/data,-p表示递归创建父目录。 - 上传文件 :
hdfs dfs -put 本地文件 HDFS路径,也可用-copyFromLocal。 - 下载文件 :
hdfs dfs -get HDFS路径 本地路径,也可用-copyToLocal。 - 删除文件或目录 :
hdfs dfs -rm -r /path,-r表示递归删除目录。 - 移动或重命名 :
hdfs dfs -mv 源路径 目标路径。 - 复制文件 :
hdfs dfs -cp 源路径 目标路径。
1.2 文件查看与统计
查看文件内容、大小和块信息等。
- 查看文件内容 :
hdfs dfs -cat /path/file,适合小文件;大文件建议用-tail查看末尾。 - 查看文件末尾 :
hdfs dfs -tail /path/file。 - 查看文件大小 :
hdfs dfs -du -h /path,-h以人类可读格式显示。 - 查看块信息 :
hdfs fsck /path/file -files -blocks,可查看文件被拆分为哪些块、分布在哪些节点。
1.3 权限与其他操作
- 修改权限 :
hdfs dfs -chmod 755 /path。 - 修改属主 :
hdfs dfs -chown user:group /path。 - 查看帮助 :
hdfs dfs -help 命令名,可查看具体命令的详细参数。
2. HDFS 写流程详解
HDFS 写流程是理解分布式存储可靠性的关键。客户端写入一个文件时,数据会经过 NameNode 的元数据管理和 DataNode 的流水线复制,最终形成多副本冗余。下面按步骤说明。
2.1 写流程步骤
- 客户端发起请求 :客户端调用
DistributedFileSystem.create(),向 NameNode 发送创建文件的 RPC 请求。 - NameNode 校验并记录元数据:NameNode 检查文件是否已存在、客户端权限是否足够。校验通过后,在命名空间中创建文件条目,但此时文件大小为 0,处于写入中状态。
- 客户端获取 DataNode 列表:NameNode 返回可用的 DataNode 列表,客户端根据副本数(默认 3)和机架感知策略,选出第一批 DataNode 作为写入目标。
- 建立数据流管道:客户端与第一个 DataNode 建立连接,第一个 DataNode 再与第二个连接,第二个与第三个连接,形成一条流水线(Pipeline)。
- 数据分包写入:客户端将数据切分为数据包(Packet,默认 64KB),按顺序写入流水线。每个 DataNode 收到一个包后,边落盘边转发给下一个 DataNode。
- 逐级确认:最后一个 DataNode 写完后,逐级向上返回确认(ACK),最终回到客户端。客户端收到确认后继续发送下一个包。
- 关闭文件 :所有数据写完后,客户端调用
close(),通知 NameNode 文件写入完成。NameNode 将文件状态改为已关闭,并持久化元数据。
2.2 关键机制
- 副本放置策略:默认第一个副本放在客户端所在节点,第二个副本放在不同机架的节点,第三个副本放在与第二个同机架的不同节点,兼顾可靠性与写入性能。
- 流水线写入:数据不是由客户端分别发给三个节点,而是沿流水线逐级转发,减少客户端网络压力。
- 故障处理:若某个 DataNode 写入失败,客户端会将该节点从管道中移除,把剩余数据发给其他节点,并通知 NameNode 调整副本数。
3. HDFS 读流程与 Python API
3.1 读流程步骤
- 客户端发起请求 :客户端调用
DistributedFileSystem.open(),向 NameNode 发送打开文件的 RPC 请求。 - NameNode 返回块位置:NameNode 查询元数据,返回文件所有块的位置信息,包括每个块所在的 DataNode 列表。
- 客户端就近读取:客户端根据网络距离选择最近的 DataNode 读取块数据。若客户端本身就是 DataNode,则直接从本地磁盘读取。
- 校验数据完整性:客户端读取数据时会校验校验和(Checksum),若发现数据损坏,会向 NameNode 报告,并从其他副本节点重新读取。
- 合并数据流:客户端按块顺序读取所有数据,合并成完整文件流返回给上层应用。
3.2 Python API 操作 HDFS
Python 操作 HDFS 常用 hdfs 库,它封装了 WebHDFS 接口。安装方式:pip install hdfs。下面给出常用操作示例。
python
from hdfs import InsecureClient
连接 HDFS,namenode 为 NameNode 主机名或 IP
client = InsecureClient('http://namenode:9870', user='hadoop')
创建目录
client.makedirs('/user/hadoop/data')
上传本地文件到 HDFS
client.upload('/user/hadoop/data/input.txt', '/local/path/input.txt')
下载 HDFS 文件到本地
client.download('/user/hadoop/data/input.txt', '/local/path/download.txt')
读取文件内容
with client.read('/user/hadoop/data/input.txt') as reader:
content = reader.read()
print(content.decode('utf-8'))
列出目录
print(client.list('/user/hadoop/data'))
删除文件
client.delete('/user/hadoop/data/input.txt')
使用 hdfs 库时,需要确保 NameNode 开启了 WebHDFS 服务(默认端口 9870)。若集群启用了 Kerberos 认证,则应改用 KerberosClient。
4. MapReduce 原理及工作流程
MapReduce 是 Hadoop 的分布式计算框架,核心思想是「分而治之」:把大规模数据集拆分成多个小任务并行处理,再汇总结果。它由 Map(映射)和 Reduce(归约)两个阶段组成。
4.1 核心原理
- Map 阶段:把输入数据拆分为键值对,经过用户自定义的 Map 函数处理后,输出中间键值对。
- Shuffle 阶段:系统自动对 Map 输出的中间结果进行分区、排序、合并和归并,把相同键的值聚合到一起,传输给 Reduce 任务。
- Reduce 阶段:接收 Shuffle 后的数据,对每个键的一组值执行用户自定义的 Reduce 函数,输出最终结果。
4.2 工作流程步骤
- 作业提交:客户端提交 Job,包含 Jar 包、输入路径、输出路径和配置信息。
- 作业初始化:ResourceManager 接收作业,分配一个 ApplicationMaster 容器,由它负责调度和监控整个作业。
- 输入分片:InputFormat 将输入数据按块边界切分为多个输入分片(Split),每个分片对应一个 Map 任务。
- Map 任务执行:每个 Map 任务读取对应分片,逐行解析为键值对,调用 Map 函数处理,输出中间结果到内存缓冲区。
- 溢写与分区:缓冲区达到阈值(默认 80%)时,中间结果按分区(Partition)写入本地磁盘,并进行排序和合并(Combine)。
- Shuffle 传输:Map 任务完成后,Reduce 任务从各个 Map 节点拉取属于自己分区的中间数据。
- Reduce 任务执行:Reduce 对拉取到的数据进行再次排序和归并,调用 Reduce 函数处理,输出最终结果写入 HDFS。
- 作业完成:所有任务完成后,ApplicationMaster 向 ResourceManager 注销,作业状态更新为成功。
4.3 详细方法建议
学习 MapReduce 时,建议从以下三个方向入手:
- 动手写 WordCount:这是 MapReduce 的 Hello World,通过实现 Map 和 Reduce 两个函数,理解键值对如何流转。
- 观察日志与计数器:运行作业后查看任务日志和计数器(Counter),能直观看到 Map 输出条数、Shuffle 字节数等关键指标。
- 结合 YARN 理解调度:MapReduce 运行在 YARN 之上,理解容器、ApplicationMaster 和 ResourceManager 的分工,有助于排查性能瓶颈。