Hadoop 基础
Hadoop是Apache基金会开发的开源分布式计算平台,是大数据技术的基石。它提供了可靠的分布式存储(HDFS)和分布式计算(MapReduce)能力,能够处理PB级别的海量数据。
Hadoop 概述
什么是 Hadoop?
Hadoop是一个由Apache基金会开发的分布式系统基础架构,主要解决海量数据的存储和分析计算问题。用户可以在不了解分布式底层细节的情况下,开发分布式程序,利用集群的威力进行高速运算和存储。
Hadoop的核心设计目标是:
- 高可靠性:通过数据多副本和自动故障转移机制保证数据安全
- 高扩展性:可以通过增加节点线性扩展集群容量
- 高效性:采用分布式并行计算,加快处理速度
- 高容错性:自动将失败的任务重新分配
Hadoop 三大核心组件
Hadoop由三个核心组件构成,它们各司其职又紧密协作:
| 组件 | 全称 | 功能 |
|---|---|---|
| HDFS | Hadoop Distributed File System | 分布式文件存储 |
| MapReduce | MapReduce | 分布式计算框架 |
| YARN | Yet Another Resource Negotiator | 资源调度管理 |
Hadoop 版本演进
| 版本 | 特点 |
|---|---|
| Hadoop 1.x | HDFS + MapReduce,计算和资源调度耦合 |
| Hadoop 2.x | 引入YARN,实现资源调度与计算分离 |
| Hadoop 3.x | 支持纠删码、多NameNode、容器化优化 |
HDFS 分布式文件系统
HDFS(Hadoop Distributed File System)是Hadoop的分布式文件存储系统,设计用于在通用硬件上运行,提供高吞吐量的数据访问。
HDFS 设计目标
- 适合大文件存储:适合存储GB到TB级别的大文件
- 流式数据访问:一次写入,多次读取的数据访问模式
- 商用硬件:运行在普通服务器上,通过冗余保证可靠性
- 高容错:自动处理节点故障,数据自动复制
HDFS 架构
HDFS采用主从架构(Master-Slave),主要由以下组件构成:
NameNode(名称节点)
NameNode是HDFS的主节点,负责管理文件系统的元数据:
- 文件目录树:维护整个文件系统的目录结构
- 文件块映射:记录每个文件由哪些数据块组成
- 数据块位置:记录每个数据块存储在哪些DataNode上
- 访问控制:管理文件的权限信息
NameNode将元数据保存在内存中以提高访问速度,同时持久化到磁盘的FsImage和EditLog文件中。
DataNode(数据节点)
DataNode是HDFS的工作节点,负责实际的数据存储:
- 数据块存储:将文件切分成固定大小的块(默认128MB)存储
- 数据块读写:响应客户端的读写请求
- 心跳汇报:定期向NameNode发送心跳和块报告
- 数据块复制:根据NameNode指令复制数据块
Secondary NameNode(辅助节点)
Secondary NameNode不是NameNode的热备,它的主要作用是:
- 合并FsImage和EditLog:定期合并元数据,减少EditLog大小
- 检查点创建:创建元数据检查点,加快NameNode启动
- 元数据备份:提供元数据的冷备份
HDFS 文件读写流程
文件读取流程
客户端读取HDFS文件的步骤如下:
- 客户端调用FileSystem.open()打开文件
- NameNode返回文件块位置信息
- 客户端连接最近的DataNode读取数据
- 读取完成后关闭连接
// HDFS文件读取示例
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path filePath = new Path("/user/data/example.txt");
FSDataInputStream inputStream = fs.open(filePath);
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
fs.close();
文件写入流程
客户端写入HDFS文件的步骤如下:
- 客户端调用FileSystem.create()创建文件
- NameNode检查权限并创建文件元数据
- 客户端将数据写入数据队列
- DataNode组成管道,依次写入数据块
- 写入完成后,客户端调用close()关闭文件
// HDFS文件写入示例
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Path filePath = new Path("/user/data/output.txt");
FSDataOutputStream outputStream = fs.create(filePath);
String content = "Hello, HDFS!";
outputStream.write(content.getBytes());
outputStream.close();
fs.close();
HDFS 常用命令
HDFS提供了丰富的命令行工具,用于文件操作:
# 查看帮助
hdfs dfs -help
# 创建目录
hdfs dfs -mkdir -p /user/hadoop/data
# 上传文件
hdfs dfs -put localfile.txt /user/hadoop/data/
# 下载文件
hdfs dfs -get /user/hadoop/data/remotefile.txt ./
# 列出目录内容
hdfs dfs -ls /user/hadoop/data/
# 查看文件内容
hdfs dfs -cat /user/hadoop/data/file.txt
# 删除文件或目录
hdfs dfs -rm -r /user/hadoop/data/olddir
# 查看文件大小
hdfs dfs -du -h /user/hadoop/data/
# 设置副本数
hdfs dfs -setrep 3 /user/hadoop/data/file.txt
HDFS 数据块与副本
数据块(Block)
HDFS将文件切分成固定大小的块进行存储:
- 默认块大小:128MB(Hadoop 2.x/3.x)
- 设计原因:减少元数据占用、减少寻址时间、支持大文件
副本机制
HDFS通过多副本机制保证数据可靠性:
- 默认副本数:3
- 副本放置策略:
- 第一个副本:优先放在客户端所在节点
- 第二个副本:放在不同机架的节点
- 第三个副本:放在第二个副本同机架的不同节点
MapReduce 分布式计算框架
MapReduce是一种分布式计算编程模型,将复杂的分布式计算分解为Map(映射)和Reduce(归约)两个阶段。
MapReduce 编程模型
MapReduce的核心思想是将计算任务分解为两个阶段:
- Map阶段:将输入数据映射为键值对,进行并行处理
- Reduce阶段:对Map输出的中间结果进行汇总
输入数据 -> Map -> (K1, V1) -> Shuffle -> (K2, List<V2>) -> Reduce -> 输出结果
MapReduce 工作流程
完整的MapReduce执行流程包括以下步骤:
- 输入分片:将输入文件切分成多个分片(Split)
- Map任务:每个分片启动一个Map任务处理
- Shuffle过程:对Map输出进行分区、排序、合并
- Reduce任务:对Shuffle后的数据进行汇总
- 输出结果:将Reduce结果写入HDFS
WordCount 示例
WordCount是MapReduce的经典入门示例,统计文本中单词出现的次数:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
// Mapper类:输入偏移量和行内容,输出单词和计数1
public class WordCountMapper
extends Mapper<LongWritable, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 将每行文本按空格分割成单词
String[] words = value.toString().split("\\s+");
for (String w : words) {
word.set(w);
// 输出 (单词, 1)
context.write(word, one);
}
}
}
// Reducer类:汇总每个单词的出现次数
public class WordCountReducer
extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
int sum = 0;
// 累加所有值
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
// 输出 (单词, 总次数)
context.write(key, result);
}
}
// Driver类:配置和提交作业
public class WordCountDriver {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf, "word count");
// 设置作业类
job.setJarByClass(WordCountDriver.class);
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
// 设置输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 设置输入输出路径
FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 提交作业并等待完成
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
Shuffle 机制详解
Shuffle是MapReduce中最核心的过程,它连接Map和Reduce阶段:
Map端Shuffle
- 环形缓冲区:Map输出先写入内存缓冲区(默认100MB)
- 溢写:缓冲区达到阈值(80%)时,溢写到磁盘
- 分区排序:溢写过程中按分区和键排序
- 合并:多个溢写文件合并成一个大文件
Reduce端Shuffle
- 拉取数据:Reduce从Map节点拉取属于自己的分区数据
- 合并:将拉取的数据合并排序
- 分组:相同Key的数据分到一组
MapReduce 数据类型
MapReduce使用Writable接口实现序列化:
| 数据类型 | Java类型 | 说明 |
|---|---|---|
| IntWritable | int | 整型 |
| LongWritable | long | 长整型 |
| FloatWritable | float | 浮点型 |
| DoubleWritable | double | 双精度 |
| Text | String | 文本 |
| BooleanWritable | boolean | 布尔型 |
| NullWritable | null | 空值 |
YARN 资源调度
YARN(Yet Another Resource Negotiator)是Hadoop 2.x引入的资源管理系统,负责集群资源的统一管理和调度。
YARN 架构
YARN采用主从架构,主要组件包括:
ResourceManager
ResourceManager是YARN的主节点,负责整个集群的资源管理:
- 资源调度:根据调度策略分配资源
- 应用管理:接收和管理应用程序提交
- 状态监控:监控集群资源使用情况
NodeManager
NodeManager是每个节点上的代理,负责单个节点的资源管理:
- 资源汇报:向ResourceManager汇报节点资源状态
- 容器管理:启动和监控容器
- 资源隔离:保证容器间的资源隔离
ApplicationMaster
ApplicationMaster是每个应用程序的管理者:
- 任务切分:将应用切分成多个任务
- 资源申请:向ResourceManager申请资源
- 任务调度:在分配的容器上调度任务
- 容错处理:处理任务失败和重试
Container
Container是YARN中资源抽象,封装了:
- CPU:虚拟CPU核心数
- 内存:可用内存大小
- 其他资源:磁盘、网络等
YARN 工作流程
应用程序在YARN上的执行流程:
- 客户端向ResourceManager提交应用
- ResourceManager分配第一个Container
- 在Container中启动ApplicationMaster
- ApplicationMaster向ResourceManager注册并申请资源
- ResourceManager返回可用的Container列表
- ApplicationMaster与NodeManager通信启动任务
- 任务执行完成,ApplicationMaster注销
YARN 调度器
YARN支持多种调度策略:
FIFO调度器
- 先进先出,简单但效率低
- 不适合多用户共享集群
容量调度器(Capacity Scheduler)
- 将集群资源划分为多个队列
- 每个队列有保证的资源配额
- 支持多租户,适合企业环境
公平调度器(Fair Scheduler)
- 所有应用公平获得资源
- 支持资源抢占
- 适合多用户交互式应用
Hadoop 集群部署
部署模式
Hadoop支持三种部署模式:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| 单机模式 | 单进程运行,无分布式特性 | 学习、调试 |
| 伪分布式 | 单机模拟分布式环境 | 开发、测试 |
| 完全分布式 | 多机集群部署 | 生产环境 |
核心配置文件
Hadoop的主要配置文件位于$HADOOP_HOME/etc/hadoop/目录:
core-site.xml
<configuration>
<!-- 指定HDFS的NameNode地址 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://namenode:9000</value>
</property>
<!-- 指定Hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/data/hadoop/tmp</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<!-- 副本数量 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- NameNode数据目录 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/data/hadoop/namenode</value>
</property>
<!-- DataNode数据目录 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>/data/hadoop/datanode</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<!-- ResourceManager地址 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>resourcemanager</value>
</property>
<!-- NodeManager运行的辅助服务 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<!-- 指定MapReduce运行在YARN上 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
集群启动流程
# 1. 格式化NameNode(仅首次)
hdfs namenode -format
# 2. 启动HDFS
start-dfs.sh
# 3. 启动YARN
start-yarn.sh
# 4. 查看进程
jps
# 5. 访问Web界面
# HDFS: http://namenode:9870
# YARN: http://resourcemanager:8088
Hadoop 高可用
生产环境中,Hadoop集群需要高可用(HA)配置,避免单点故障。
HDFS 高可用
HDFS高可用通过Active/Standby NameNode实现:
- 主备切换:Active NameNode故障时,Standby自动接管
- 共享存储:使用Quorum Journal Manager或NFS共享EditLog
- ZooKeeper协调:自动故障检测和主备选举
YARN 高可用
YARN高可用通过ResourceManager HA实现:
- 主备切换:Active RM故障时,Standby RM接管
- 状态恢复:Standby RM从ZooKeeper恢复应用状态
- 透明切换:客户端自动重连到新的Active RM
小结
本章介绍了Hadoop的核心组件和基本使用:
- HDFS:分布式文件系统,提供高可靠的文件存储
- MapReduce:分布式计算框架,适合离线批处理
- YARN:资源调度系统,管理集群资源分配
Hadoop是大数据技术的基础,理解其原理对于学习后续的Spark、Flink等框架非常重要。在实际应用中,Hadoop通常与Hive、HBase等组件配合使用,构建完整的大数据处理平台。