1. 大数据概述
大数据是指无法用传统工具处理的海量数据集合,其核心特征通常概括为 4V:Volume(数据量大)、Velocity(处理速度快)、Variety(数据类型多样)、Value(价值密度低)。学习大数据技术,首先需要理解分布式存储和分布式计算的基本思想。
1.1 什么是大数据
大数据并不是一个绝对的概念,而是相对于传统数据处理能力而言的。当数据量达到 TB、PB 甚至 EB 级别,传统的关系型数据库和单机处理工具已经无法在可接受的时间内完成存储、计算和分析时,我们就称之为大数据。大数据不仅指数据规模大,还强调数据的多样性、产生速度和潜在价值。
1.2 4V 特征详解
大数据的 4V 特征是其最核心的判别标准,下面逐一展开说明:
- Volume(数据量大):数据规模从 GB 级跃升到 TB、PB 级甚至更高。例如电商平台每天产生的交易日志、社交平台每天产生的用户行为数据,都是海量数据的典型来源。
- Velocity(处理速度快):数据产生和更新的速度极快,要求系统能够实时或近实时地采集和处理。例如股票交易数据、物联网传感器数据,都需要在秒级甚至毫秒级完成响应。
- Variety(数据类型多样):数据来源和格式丰富,包括结构化数据(如数据库表)、半结构化数据(如 JSON、XML 日志)和非结构化数据(如文本、图片、音视频)。不同类型的数据需要不同的存储和处理方式。
- Value(价值密度低):海量数据中真正有价值的信息占比很低,需要通过复杂的分析挖掘才能提取出高价值内容。例如监控视频中可能只有几秒钟的异常事件值得关注。
1.3 分布式存储与分布式计算
面对海量数据,单台机器的存储容量和计算能力都存在瓶颈,因此大数据技术的核心思想是「分而治之」:
- 分布式存储:将数据切分成多个数据块,分散存储在多台机器上,通过副本机制保证数据不丢失。典型代表是 HDFS(Hadoop 分布式文件系统)。
- 分布式计算:将一个大任务拆分成多个小任务,分发到多台机器上并行执行,最后汇总结果。典型代表是 MapReduce 计算模型。
理解这两个基本思想,是后续学习 Hadoop、HDFS 和 MapReduce 的重要基础。
2. Hadoop 环境搭建
Hadoop 是大数据生态的基础框架,包含 HDFS(分布式文件系统)和 MapReduce(分布式计算模型)。环境搭建是入门的第一步,下面以单机伪分布式模式为例,详细介绍从 JDK 安装到 Hadoop 启动验证的完整步骤。
2.1 环境准备
在开始搭建之前,需要准备一台 Linux 系统机器(推荐 CentOS 7 或 Ubuntu 18.04+),并确认以下基础条件:
- 操作系统:Linux 64 位系统,建议内存不低于 2GB,磁盘剩余空间不低于 20GB。
- JDK 版本:Hadoop 2.x 需要 JDK 1.7+,Hadoop 3.x 需要 JDK 1.8+,推荐使用 JDK 1.8。
- Hadoop 版本:本文以 Hadoop 3.3.4 为例进行演示。
- 网络配置:确保机器可以访问外网,以便下载 JDK 和 Hadoop 安装包。
2.2 安装 JDK
Hadoop 依赖 Java 运行环境,因此需要先安装 JDK。这里以 Oracle JDK 1.8 为例,步骤如下:
- 下载 JDK 安装包(如 jdk-8u202-linux-x64.tar.gz),并上传到服务器 /opt 目录。
- 解压 JDK 到指定目录:
tar -zxvf jdk-8u202-linux-x64.tar.gz -C /opt - 配置环境变量,编辑
/etc/profile文件,在末尾追加以下内容:
bash
export JAVA_HOME=/opt/jdk1.8.0_202
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
- 使环境变量生效并验证安装:
source /etc/profile,然后执行java -version,看到 Java 版本信息即表示安装成功。
2.3 配置 SSH 免密登录
Hadoop 的 NameNode 需要通过 SSH 无密码登录到各 DataNode 节点,即使是单机伪分布式模式也需要配置本机免密登录。步骤如下:
- 生成密钥对:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa - 将公钥追加到 authorized_keys:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys - 设置权限:
chmod 600 ~/.ssh/authorized_keys - 验证免密登录:
ssh localhost,如果无需输入密码即可登录,说明配置成功。
2.4 下载并解压 Hadoop
从 Apache 官网或镜像站下载 Hadoop 安装包,然后解压到指定目录:
bash
wget https://archive.apache.org/dist/hadoop/common/hadoop-3.3.4/hadoop-3.3.4.tar.gz
tar -zxvf hadoop-3.3.4.tar.gz -C /opt
mv /opt/hadoop-3.3.4 /opt/hadoop
解压完成后,需要配置 Hadoop 的环境变量,编辑 /etc/profile 追加:
bash
export HADOOP_HOME=/opt/hadoop
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
执行 source /etc/profile 使配置生效,然后运行 hadoop version 验证 Hadoop 是否安装成功。
2.5 修改核心配置文件
Hadoop 的配置主要集中在 $HADOOP_HOME/etc/hadoop 目录下,需要修改以下 5 个核心文件:
(1)hadoop-env.sh:设置 Java 环境变量
bash
export JAVA_HOME=/opt/jdk1.8.0_202
(2)core-site.xml:配置 NameNode 地址和临时目录
xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/hadoop/tmp</value>
</property>
</configuration>
(3)hdfs-site.xml:配置副本数和 NameNode 数据目录
xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/opt/hadoop/namenode</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/opt/hadoop/datanode</value>
</property>
</configuration>
(4)mapred-site.xml:指定 MapReduce 使用 YARN 调度
xml
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
(5)yarn-site.xml:配置 YARN 的资源管理服务
xml
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
2.6 格式化 NameNode
首次启动 Hadoop 前,需要格式化 NameNode 的元数据目录。执行以下命令:
bash
hdfs namenode -format
看到 successfully formatted 提示即表示格式化成功。注意:格式化操作会清空 NameNode 的元数据,只在首次安装时执行一次。
2.7 启动 Hadoop 集群
格式化完成后,依次启动 HDFS 和 YARN 服务:
bash
start-dfs.sh
start-yarn.sh
启动完成后,可以使用 jps 命令查看 Java 进程,正常情况下应看到以下 5 个进程:
- NameNode:HDFS 主节点,管理元数据。
- DataNode:HDFS 从节点,存储数据块。
- SecondaryNameNode:辅助 NameNode 合并元数据。
- ResourceManager:YARN 资源管理器。
- NodeManager:YARN 节点管理器。
2.8 验证环境
环境搭建完成后,可以通过以下方式验证是否正常运行:
- 访问 HDFS Web 界面:浏览器打开
http://localhost:9870,可以看到 NameNode 的状态和集群信息。 - 访问 YARN Web 界面:浏览器打开
http://localhost:8088,可以查看集群资源和任务调度情况。 - 执行一个简单的 HDFS 命令测试:
hdfs dfs -mkdir /test,然后执行hdfs dfs -ls /查看根目录,如果能看到 test 目录,说明 HDFS 读写正常。
至此,Hadoop 单机伪分布式环境搭建完成。后续可以在此基础上继续学习 HDFS 文件操作、MapReduce 编程以及 YARN 资源调度等内容。
3. HDFS 架构
HDFS(Hadoop Distributed File System)是 Hadoop 生态中的分布式文件系统,采用主从(Master/Slave)架构,设计目标是运行在廉价商用硬件上,提供高吞吐、高容错的海量数据存储能力。下面从核心组件、数据块机制、副本策略和读写流程四个方面详细介绍。
3.1 核心组件
HDFS 由以下三个核心组件构成:
- NameNode(主节点):负责管理整个文件系统的元数据,包括文件目录结构、文件与数据块的映射关系、数据块的副本位置等。NameNode 不直接存储数据,而是维护一张「元数据表」,客户端的所有读写请求都先经过 NameNode 获取数据块位置信息。
- DataNode(从节点):负责实际存储数据块,并定期向 NameNode 上报自身的数据块列表和健康状态。一个集群通常有多个 DataNode,数据以块为单位分散存储在各 DataNode 上。
- SecondaryNameNode(辅助节点):并非 NameNode 的热备,而是定期合并 NameNode 的编辑日志(EditLog)与镜像文件(FsImage),减轻 NameNode 的负担,并在 NameNode 故障时辅助恢复元数据。
3.2 数据块(Block)机制
HDFS 将文件切分为固定大小的数据块进行存储,默认块大小为 128MB(Hadoop 2.x 及以后版本)。数据块机制带来以下好处:
- 支持超大文件:一个文件可以被切分成多个块,分散存储在不同 DataNode 上,突破了单机磁盘容量限制。
- 简化存储管理:以块为最小存储单元,便于统一管理和复制。
- 提升容错能力:单个块损坏只需修复该块,无需重建整个文件。
3.3 副本机制与容错
为保证数据可靠性,HDFS 默认将每个数据块复制为 3 份副本,并遵循「机架感知」策略放置副本:
- 第一个副本放在客户端所在节点(若客户端不在集群内,则随机选择节点)。
- 第二个副本放在与第一个副本不同机架的节点上。
- 第三个副本放在与第二个副本相同机架的不同节点上。
这种策略既保证了数据的高可用性,又兼顾了网络带宽和容错能力。当某个 DataNode 宕机或数据块损坏时,NameNode 会检测到副本数不足,并自动调度在其他节点上重新复制副本,使副本数恢复到设定值。
3.4 读写流程
读流程:客户端向 NameNode 请求文件元数据,NameNode 返回文件对应的数据块列表及每个块的副本位置;客户端根据就近原则,选择距离最近的 DataNode 读取数据块,并校验数据完整性。
写流程:客户端向 NameNode 发起写请求,NameNode 返回可用的 DataNode 列表;客户端将数据切分为数据包(Packet),按流水线方式依次写入第一个 DataNode,再由第一个 DataNode 转发给第二个、第三个 DataNode,形成复制流水线;全部写入成功后,客户端通知 NameNode 更新元数据。
3.5 优缺点总结
HDFS 的优势在于高吞吐、高容错、可扩展,适合大规模批处理场景;其局限性在于不适合低延迟实时访问、小文件存储效率低、不支持随机写入和文件修改。理解这些特性,有助于在实际项目中合理选型。
4. MapReduce 原理
MapReduce 是一种分布式计算模型,由 Google 在 2004 年提出,其核心思想是「分而治之」:将大规模数据处理任务拆分为 Map(映射)和 Reduce(归约)两个阶段,在多台机器上并行执行,最终汇总结果。下面从核心概念、执行流程、Shuffle 机制和 WordCount 示例四个方面详细介绍。
4.1 核心概念
MapReduce 围绕两个核心函数展开:
- Map(映射):接收输入数据,将其拆分为若干键值对(Key-Value),并对每个键值对执行用户定义的映射逻辑,输出中间结果。Map 阶段可以并行处理,每个输入分片对应一个 Map 任务。
- Reduce(归约):接收 Map 阶段输出的中间结果,将具有相同 Key 的 Value 进行合并、汇总,输出最终结果。Reduce 阶段同样可以并行执行,每个 Reduce 任务处理一部分 Key 范围。
除了 Map 和 Reduce,MapReduce 还涉及以下关键概念:
- Job(作业):一个完整的 MapReduce 任务,包含输入数据、Map 逻辑、Reduce 逻辑和输出路径等配置。
- Task(任务):一个 Job 会被拆分为多个 Map Task 和多个 Reduce Task,分别在不同节点上并行执行。
- InputSplit(输入分片):输入数据被逻辑切分为多个分片,每个分片对应一个 Map Task。分片大小通常与 HDFS 数据块大小一致(默认 128MB)。
- Key-Value 对:MapReduce 处理的数据以键值对形式组织,Map 输入和输出、Reduce 输入和输出都是键值对。
4.2 执行流程
一个完整的 MapReduce Job 执行流程如下:
- 作业提交:客户端将 Job 提交给 YARN 的 ResourceManager,ResourceManager 分配一个 ApplicationMaster 来管理该作业。
- 输入分片:框架将输入数据按 InputSplit 切分为多个分片,每个分片分配给一个 Map Task。
- Map 阶段:每个 Map Task 读取对应分片的数据,逐条调用用户定义的 map 函数,输出中间键值对,并写入本地磁盘的环形缓冲区。
- Shuffle 阶段:Map 输出的中间结果经过分区(Partition)、排序(Sort)和合并(Combine)后,通过网络传输到对应的 Reduce Task 所在节点。
- Reduce 阶段:每个 Reduce Task 拉取属于自己分区的中间结果,按 Key 分组后调用用户定义的 reduce 函数,输出最终结果并写入 HDFS。
- 作业完成:所有 Task 执行完毕后,ApplicationMaster 通知客户端作业完成,并返回执行状态和统计信息。
4.3 Shuffle 机制详解
Shuffle 是 MapReduce 中最核心也最复杂的环节,它负责将 Map 阶段的输出传输到 Reduce 阶段,整个过程分为 Map 端和 Reduce 端两部分。
Map 端 Shuffle:
- Map 函数输出的键值对先写入内存中的环形缓冲区(默认 100MB)。
- 当缓冲区达到阈值(默认 80%)时,后台线程开始将数据溢写(Spill)到本地磁盘。
- 溢写前会进行分区(Partition),即根据 Key 的哈希值决定该键值对属于哪个 Reduce 分区。
- 每个分区内部会进行排序(Sort),如果配置了 Combiner,还会在排序后先做一次本地合并,减少传输数据量。
- 多次溢写会产生多个小文件,最终会将这些小文件合并(Merge)成一个大文件,并建立索引以便 Reduce 端拉取。
Reduce 端 Shuffle:
- Reduce Task 启动后,会启动多个复制线程,从各个 Map Task 的输出中拉取属于自己分区的数据。
- 拉取的数据先放入内存缓冲区,超过阈值后溢写到磁盘。
- 所有数据拉取完成后,Reduce 端会对数据进行再次排序和合并,将相同 Key 的 Value 聚集在一起。
- 最后将分组后的数据交给 reduce 函数处理。
4.4 WordCount 示例
以经典的单词计数为例,假设输入文件内容为:
text
hello world
hello hadoop
world hadoop
Map 阶段:将每行文本拆分为单词,输出键值对,Key 为单词,Value 为 1。
text
(hello, 1) (world, 1)
(hello, 1) (hadoop, 1)
(world, 1) (hadoop, 1)
Shuffle 阶段:按 Key 进行分区、排序和分组,得到:
text
(hadoop, [1, 1])
(hello, [1, 1])
(world, [1, 1])
Reduce 阶段:对每个 Key 的 Value 列表求和,输出最终结果:
text
(hadoop, 2)
(hello, 2)
(world, 2)
通过这个简单示例可以看出,MapReduce 将复杂的分布式计算抽象为两个简单的函数,开发者只需关注业务逻辑,无需关心任务调度、数据分发和容错等底层细节。
5. Python 操作 MapReduce
除了使用 Java 编写 MapReduce 程序,也可以通过 Python 结合 Hadoop Streaming 实现。Hadoop Streaming 允许用户使用任意可执行脚本(如 Python、Shell)作为 Mapper 和 Reducer,脚本从标准输入读取数据,经过处理后输出到标准输出,从而完成分布式计算任务。下面从原理、环境准备、WordCount 实战和运行调试四个方面详细介绍。
5.1 Hadoop Streaming 原理
Hadoop Streaming 是 Hadoop 提供的一个通用工具,它本身是一个 Java 程序,负责与 YARN 交互、管理任务生命周期,并将数据通过标准输入输出(stdin/stdout)与用户脚本进行交互。其工作流程如下:
- Hadoop Streaming 为每个 Map Task 启动一个 Python 进程,将输入分片的数据逐行写入该进程的标准输入。
- Python Mapper 脚本从标准输入读取每一行,处理后通过标准输出输出键值对,格式为「Key + 制表符 + Value」。
- Shuffle 阶段由 Hadoop 框架完成,对 Mapper 输出的键值对进行分区、排序和分组。
- Hadoop Streaming 为每个 Reduce Task 启动一个 Python 进程,将分组后的数据逐行写入该进程的标准输入。
- Python Reducer 脚本从标准输入读取数据,汇总后通过标准输出输出最终结果。
这种设计使得开发者无需编写 Java 代码,只需用 Python 实现 Map 和 Reduce 逻辑即可完成分布式计算。
5.2 环境准备
在运行 Python MapReduce 之前,需要确保以下环境就绪:
- Hadoop 集群已正常启动(参考第 2 章环境搭建)。
- Python 环境已安装(推荐 Python 3.x,Hadoop 3.x 默认支持)。
- 准备一个输入文件并上传到 HDFS,例如:
bash
hdfs dfs -mkdir -p /input
hdfs dfs -put /opt/input.txt /input/
5.3 WordCount 实战
下面以单词计数为例,演示如何用 Python 编写 Mapper 和 Reducer。
(1)编写 Mapper 脚本 mapper.py
python
#!/usr/bin/env python3
import sys
for line in sys.stdin:
# 去除首尾空白字符
line = line.strip()
# 按空格拆分单词
words = line.split()
# 输出键值对,Key 为单词,Value 为 1
for word in words:
print(f"{word}\t1")
(2)编写 Reducer 脚本 reducer.py
python
#!/usr/bin/env python3
import sys
current_word = None
current_count = 0
for line in sys.stdin:
line = line.strip()
word, count = line.split("\t", 1)
count = int(count)
# 如果当前单词与上一个相同,累加计数
if current_word == word:
current_count += count
else:
# 输出上一个单词的统计结果
if current_word:
print(f"{current_word}\t{current_count}")
current_word = word
current_count = count
输出最后一个单词的统计结果
if current_word:
print(f"{current_word}\t{current_count}")
(3)本地测试脚本
在提交到 Hadoop 之前,建议先用管道在本地验证脚本逻辑是否正确:
bash
echo "hello world hello hadoop" | python3 mapper.py | sort | python3 reducer.py
预期输出:
text
hadoop 1
hello 2
world 1
(4)提交到 Hadoop 集群运行
使用 hadoop-streaming 工具提交作业,命令如下:
bash
hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-3.3.4.jar \
-input /input/input.txt \
-output /output/wordcount \
-mapper "python3 mapper.py" \
-reducer "python3 reducer.py" \
-file mapper.py \
-file reducer.py
参数说明:
- -input:HDFS 上的输入路径。
- -output:HDFS 上的输出路径(必须不存在,否则会报错)。
- -mapper / -reducer:指定 Mapper 和 Reducer 的执行命令。
- -file:将本地脚本文件分发到集群的所有节点,确保每个 Task 都能访问。
(5)查看运行结果
bash
hdfs dfs -cat /output/wordcount/part-00000
输出结果:
text
hadoop 2
hello 2
world 2
5.4 运行调试与常见问题
在实际运行中,可能会遇到以下常见问题:
- 脚本没有执行权限 :如果直接执行脚本而不是通过 python3 命令,需要先赋予执行权限:
chmod +x mapper.py reducer.py。 - 输出路径已存在 :Hadoop 要求输出路径不能预先存在,运行前需删除旧目录:
hdfs dfs -rm -r /output/wordcount。 - Python 版本不一致:集群各节点需安装相同版本的 Python,否则可能导致脚本无法运行。
- 中文编码问题 :如果处理中文数据,建议在脚本开头添加
# -*- coding: utf-8 -*-,并确保输入文件编码为 UTF-8。 - 查看日志:作业失败时,可通过 YARN Web 界面(http://localhost:8088)查看任务日志,定位具体错误。
通过以上步骤,即可使用 Python 完成 MapReduce 分布式计算任务。相比 Java 开发,Python + Hadoop Streaming 的方式代码更简洁、上手更快,非常适合快速原型验证和数据分析场景。
6. 学习路线总结
建议按照「大数据介绍 → Hadoop 环境搭建 → HDFS 架构 → MapReduce 原理 → Python 操作 MapReduce」的顺序学习,配合视频教程和动手实验,逐步掌握大数据核心技术。