【集群模式】第一个MapReduce程序——WordCount

【集群模式】第一个MapReduce程序------WordCount_在3节点完全分布式Hadoop集群上运行MapReduce任务


前言

上一篇文章我们完成了Hadoop完全分布式集群的搭建,成功启动了HDFS和YARN。本文将在这个3节点集群上,运行我们的第一个MapReduce程序------WordCount 。本文采用集群模式,直接在Linux集群上通过命令行提交作业,让任务真正分布式运行在YARN上。


一、MapReduce核心原理回顾

一个MapReduce程序主要包括三部分:Mapper类Reducer类执行类(Driver)

1.1 Map阶段

将输入文件的每一行按空格切分,提取单词,转为 <key, 1> 的形式:

  • KEYIN:每行的偏移量(LongWritable)
  • VALUEIN:当前行的文本内容(Text)
  • KEYOUT:切分后的单词(Text)
  • VALUEOUT:固定值 1(LongWritable)

1.2 Reduce阶段

将Map阶段输出的相同key(单词)对应的value(1)进行累加,得到单词出现总次数:

  • KEYIN:单词(Text)
  • VALUEIN:该单词出现次数的集合(Iterable)
  • KEYOUT:单词(Text)
  • VALUEOUT:总次数(LongWritable)

二、集群环境确认

在运行程序前,先确认集群状态正常:

2.1 检查HDFS和YARN是否启动

bash 复制代码
[atguigu@hadoop102 ~]$ jpsall
=============== hadoop102 ===============
1234 NameNode
1567 DataNode
1890 NodeManager
2345 JobHistoryServer
=============== hadoop103 ===============
2341 DataNode
2678 ResourceManager
2890 NodeManager
=============== hadoop104 ===============
3456 DataNode
3789 SecondaryNameNode
3901 NodeManager

2.2 Web页面确认

组件 访问地址 状态
HDFS NameNode http://hadoop102:9870 Live Nodes应为3
YARN ResourceManager http://hadoop103:8088 Active Nodes应为3
JobHistory http://hadoop102:19888 正常访问

三、准备输入数据

3.1 创建HDFS输入目录

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -mkdir -p /wordcount/input

3.2 创建测试文件并上传

在本地创建测试文件:

bash 复制代码
[atguigu@hadoop102 ~]$ vim word.txt

输入内容(模拟大数据技术栈关键词):

复制代码
hadoop hdfs yarn mapreduce
hadoop spark flink kafka
hive hbase sqoop flume
hadoop spark hive pig
java python scala sql
hadoop hdfs hive spark

上传到HDFS:

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -put word.txt /wordcount/input/

3.3 验证上传成功

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -ls /wordcount/input/
Found 1 items
-rw-r--r--   3 atguigu supergroup        120 2024-04-25 09:00 /wordcount/input/word.txt

[atguigu@hadoop102 ~]$ hadoop fs -cat /wordcount/input/word.txt
hadoop hdfs yarn mapreduce
hadoop spark flink kafka
hive hbase sqoop flume
hadoop spark hive pig
java python scala sql
hadoop hdfs hive spark

四、运行官方WordCount示例

Hadoop安装包中自带了WordCount示例jar包,我们先运行官方示例,验证集群是否正常。

4.1 执行命令

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop jar /opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar wordcount /wordcount/input /wordcount/output

4.2 命令解析

部分 说明
hadoop jar 提交jar包到Hadoop集群运行
/opt/module/hadoop-3.1.3/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar 官方示例jar包路径
wordcount 指定运行WordCount程序
/wordcount/input HDFS上的输入路径
/wordcount/output HDFS上的输出路径(必须不存在,否则报错

4.3 查看执行日志

执行过程中会输出Map和Reduce的进度:

复制代码
2024-04-25 09:05:01 INFO mapreduce.Job: Running job: job_1714012800000_0001
2024-04-25 09:05:10 INFO mapreduce.Job: map 0% reduce 0%
2024-04-25 09:05:18 INFO mapreduce.Job: map 100% reduce 0%
2024-04-25 09:05:25 INFO mapreduce.Job: map 100% reduce 100%
2024-04-25 09:05:26 INFO mapreduce.Job: Job job_1714012800000_0001 completed successfully

4.4 查看输出结果

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -ls /wordcount/output/
Found 2 items
-rw-r--r--   3 atguigu supergroup          0 2024-04-25 09:05 /wordcount/output/_SUCCESS
-rw-r--r--   3 atguigu supergroup        102 2024-04-25 09:05 /wordcount/output/part-r-00000

查看统计结果:

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -cat /wordcount/output/part-r-00000
flink	1
flume	1
hadoop	4
hbase	1
hdfs	2
hive	3
java	1
kafka	1
mapreduce	1
pig	1
python	1
scala	1
spark	3
sqoop	1
sql	1
yarn	1

4.5 输出文件说明

文件名 说明
_SUCCESS 任务执行成功的标志文件,内容为空
part-r-00000 Reduce任务的输出结果文件,r表示Reduce输出,00000表示第0个Reduce任务

如果有多个Reduce任务,会生成 part-r-00000part-r-00001 等多个文件。


五、自定义WordCount程序(Java开发)

官方示例只能按空格切分,实际业务中可能需要自定义分隔符、过滤停用词等。下面我们编写自定义的WordCount程序。

5.1 开发环境准备

在hadoop102上安装Maven(或直接使用IDEA开发后上传jar包):

bash 复制代码
[atguigu@hadoop102 ~]$ sudo yum install -y maven

5.2 创建Maven项目

bash 复制代码
[atguigu@hadoop102 ~]$ mkdir -p ~/projects/wordcount
[atguigu@hadoop102 ~]$ cd ~/projects/wordcount

创建 pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu</groupId>
    <artifactId>wordcount</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <hadoop.version>3.1.3</hadoop.version>
    </properties>

    <dependencies>
        <!-- Hadoop客户端依赖 -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.30</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- 打包插件:将依赖一起打包 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

5.3 Hadoop序列化类型说明

Hadoop类型 Java对应类型 说明
Text String 可变长度文本
LongWritable long 长整型
IntWritable int 整型
FloatWritable float 浮点型
DoubleWritable double 双精度浮点型
BooleanWritable boolean 布尔型
NullWritable null 空值
ArrayWritable 数组 数组类型
MapWritable Map Map类型

5.4 编写Mapper类

创建目录结构:

bash 复制代码
[atguigu@hadoop102 wordcount]$ mkdir -p src/main/java/com/atguigu/mapreduce

创建 WordCountMapper.java

java 复制代码
package com.atguigu.mapreduce;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.util.StringUtils;

import java.io.IOException;

/**
 * WordCount Mapper类
 * 
 * 输入:  KEYIN=LongWritable(行偏移量) VALUEIN=Text(一行文本)
 * 输出:  KEYOUT=Text(单词)         VALUEOUT=LongWritable(计数1)
 */
public class WordCountMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
    
    // 复用对象,减少GC压力
    private Text outKey = new Text();
    private final static LongWritable outValue = new LongWritable(1);

    @Override
    protected void map(LongWritable key, Text value, Context context) 
            throws IOException, InterruptedException {
        
        // 获取一行数据
        String line = value.toString();
        
        // 使用Hadoop的StringUtils.split按空格切分(性能优于Java原生split)
        // 支持多个空格、制表符等空白字符
        String[] words = StringUtils.split(line, ' ');
        
        // 遍历单词,输出 <单词, 1>
        for (String word : words) {
            // 过滤空字符串
            if (word != null && !word.trim().isEmpty()) {
                outKey.set(word.trim().toLowerCase()); // 转为小写,统一统计
                context.write(outKey, outValue);
            }
        }
    }
}

5.5 编写Reducer类

创建 WordCountReducer.java

java 复制代码
package com.atguigu.mapreduce;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * WordCount Reducer类
 * 
 * 输入:  KEYIN=Text(单词)              VALUEIN=Iterable<LongWritable>(计数集合)
 * 输出:  KEYOUT=Text(单词)             VALUEOUT=LongWritable(总次数)
 */
public class WordCountReducer extends Reducer<Text, LongWritable, Text, LongWritable> {
    
    private LongWritable outValue = new LongWritable();

    @Override
    protected void reduce(Text key, Iterable<LongWritable> values, Context context) 
            throws IOException, InterruptedException {
        
        // 累加单词出现次数
        long sum = 0;
        for (LongWritable value : values) {
            sum += value.get();
        }
        
        outValue.set(sum);
        context.write(key, outValue);
    }
}

5.6 编写Driver执行类

创建 WordCountDriver.java

java 复制代码
package com.atguigu.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * WordCount Driver类
 * 配置并提交MapReduce作业
 */
public class WordCountDriver {

    public static void main(String[] args) throws IOException, 
            ClassNotFoundException, InterruptedException {
        
        // 参数校验:需要输入路径和输出路径
        if (args.length != 2) {
            System.err.println("Usage: WordCountDriver <input path> <output path>");
            System.exit(-1);
        }

        // 1. 获取配置和Job对象
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "Custom WordCount");
        
        // 2. 设置Jar包路径(集群运行必须)
        job.setJarByClass(WordCountDriver.class);
        
        // 3. 关联Mapper和Reducer
        job.setMapperClass(WordCountMapper.class);
        job.setReducerClass(WordCountReducer.class);
        
        // 4. 设置Map输出KV类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);
        
        // 5. 设置最终输出KV类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);
        
        // 6. 设置输入输出路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));
        
        // 7. 提交作业并等待完成
        boolean result = job.waitForCompletion(true);
        
        // 8. 根据结果退出
        System.exit(result ? 0 : 1);
    }
}

5.7 项目完整目录结构

复制代码
wordcount/
├── pom.xml
└── src/
    └── main/
        └── java/
            └── com/
                └── atguigu/
                    └── mapreduce/
                        ├── WordCountMapper.java
                        ├── WordCountReducer.java
                        └── WordCountDriver.java

5.8 编译打包

bash 复制代码
[atguigu@hadoop102 wordcount]$ mvn clean package

打包成功后,会在 target/ 目录生成 wordcount-1.0-SNAPSHOT.jar


六、提交自定义程序到集群运行

6.1 准备新的输入数据

bash 复制代码
# 删除之前的输出目录(Hadoop不允许输出目录已存在)
[atguigu@hadoop102 ~]$ hadoop fs -rm -r /wordcount/output

# 创建新的输入数据(包含大小写和多余空格,测试我们的自定义程序)
[atguigu@hadoop102 ~]$ vim word2.txt

输入内容:

复制代码
Hadoop HDFS YARN MapReduce
Hadoop  Spark  Flink
hadoop spark HIVE hive
  Java  java  JAVA  
Python scala SQL

上传:

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -put word2.txt /wordcount/input2/

6.2 提交作业

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop jar ~/projects/wordcount/target/wordcount-1.0-SNAPSHOT.jar com.atguigu.mapreduce.WordCountDriver /wordcount/input2 /wordcount/output2

6.3 查看YARN上的作业

浏览器访问:http://hadoop103:8088

可以看到作业运行状态:

  • Application Type: MAPREDUCE
  • State: FINISHED
  • FinalStatus: SUCCEEDED

6.4 查看输出结果

bash 复制代码
[atguigu@hadoop102 ~]$ hadoop fs -cat /wordcount/output2/part-r-00000
flink	1
hadoop	3
hdfs	1
hive	2
java	3
mapreduce	1
python	1
scala	1
spark	2
sql	1
yarn	1

可以看到:

  • 所有单词已转为小写(Javajava
  • 多余空格已被过滤
  • 统计结果正确

七、集群模式 vs 本地模式对比

对比项 本地模式(参考文章) 集群模式(本文)
运行环境 Windows IDEA Linux Hadoop集群
数据存储 本地文件系统 HDFS分布式文件系统
计算资源 单机CPU/内存 多节点分布式计算
提交方式 右键运行main方法 hadoop jar 命令提交
YARN调度 不涉及 ResourceManager统一调度
适用场景 本地开发调试 生产环境运行
扩展性 可扩展至数千节点
容错性 任务失败自动重试

八、常见问题与解决

8.1 输出目录已存在

复制代码
org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://hadoop102:8020/wordcount/output already exists

解决:Hadoop不允许输出目录已存在,先删除或更换输出路径:

bash 复制代码
hadoop fs -rm -r /wordcount/output

8.2 权限不足

复制代码
org.apache.hadoop.security.AccessControlException: Permission denied: user=atguigu, access=WRITE, inode="/":root:supergroup:drwxr-xr-x

解决 :在 core-site.xml 中配置静态用户:

xml 复制代码
<property>
    <name>hadoop.http.staticuser.user</name>
    <value>atguigu</value>
</property>

或在HDFS上创建用户目录并授权:

bash 复制代码
hadoop fs -mkdir -p /user/atguigu
hadoop fs -chown atguigu:atguigu /user/atguigu

8.3 Container被杀死

复制代码
Container killed by the ApplicationMaster.
Container exited with a non-zero exit code 143.

解决:通常是内存不足,增大任务内存配置:

bash 复制代码
# 提交时指定内存
hadoop jar wordcount.jar com.atguigu.mapreduce.WordCountDriver \
    -Dmapreduce.map.memory.mb=2048 \
    -Dmapreduce.reduce.memory.mb=4096 \
    /input /output

8.4 数据倾斜

某些Reduce任务处理数据量远大于其他,导致整体延迟。

解决

  • 自定义Partitioner打散热点key
  • 使用Combiner进行Map端预聚合
  • 调整Reduce任务数:job.setNumReduceTasks(10)

九、作业监控与日志查看

9.1 YARN Web UI查看

访问 http://hadoop103:8088,点击完成的作业ID,可以查看:

信息 说明
Application Overview 作业概览,包括启动时间、结束时间、运行状态
ApplicationMaster AM的日志链接
Logs 所有Container的日志聚合
Map Tasks Map任务列表及状态
Reduce Tasks Reduce任务列表及状态

9.2 命令行查看日志

bash 复制代码
# 查看指定application的日志
yarn logs -applicationId application_1714012800000_0001

# 查看特定Container的日志
yarn logs -applicationId application_1714012800000_0001 -containerId container_xxx

9.3 JobHistory查看历史作业

访问 http://hadoop102:19888/jobhistory

可以查看已完成的作业详情,包括:

  • 作业配置参数
  • 每个Map/Reduce任务的耗时
  • 任务失败原因和重试记录

十、总结

本文在3节点完全分布式Hadoop集群上,完成了第一个MapReduce程序------WordCount的开发和运行:

步骤 内容
1 确认集群环境(HDFS + YARN正常运行)
2 准备HDFS输入数据
3 运行官方WordCount示例验证集群
4 自定义Java程序(Mapper + Reducer + Driver)
5 Maven打包并提交到集群运行
6 查看YARN作业监控和输出结果

关键点

  • 集群模式下数据必须存储在HDFS上
  • 输出目录不能提前存在
  • job.setJarByClass() 是集群运行的关键
  • YARN Web UI是排查问题的重要工具

如果这篇文章对你有帮助,欢迎点赞、收藏、评论三连!有问题可以在评论区留言交流~

相关推荐
塔能物联运维11 小时前
不止降温,更能控温|两相液冷重构高密度算力热管理新模式
大数据
Francek Chen11 小时前
【大数据存储与管理】云数据库:03 云数据库系统架构
大数据·数据库·分布式·架构
pearbing11 小时前
B站搜索流量突围:关键词精准布局,打造高适配SEO运营体系
大数据·b站·b站关键词排名·b站排名优化·b站seo·b站搜索优化
互联网科技看点11 小时前
2026年,园世Yuansea:以专业之名,重塑运动音频边界
大数据·人工智能·音视频
金融小师妹11 小时前
基于AI通胀风险识别模型与联储决策框架的政策分歧研究:鹰派权重上升后的全球流动性再定价分析
大数据·深度学习·逻辑回归·线性回归
Gofarlic_OMS11 小时前
Mastercam浮动许可利用率低:软件许可浪费,回收再分配
java·大数据·开发语言·架构·制造
维双云11 小时前
搭建商城型小程序,具备预约挂号功能,供医院使用,该怎么做?
大数据
云栖梦泽在11 小时前
AI安全实战:AI供应链安全防护的实战案例
大数据·人工智能·安全
weelinking12 小时前
2026年三大主流大模型深度对比:GPT-5.5、Claude 4.6与DeepSeek V4谁更值得选择?
java·大数据·人工智能·git·python·gpt·github
想ai抽12 小时前
Kylin 全局字典机制与 StarRocks Bitmap 精确去重技术调研
大数据·starrocks·kylin