Windows 下运行 Hadoop 并部署到 AWS EMR 指南

本文详细介绍如何在 Windows 10 环境下开发和运行 Hadoop MapReduce 程序,并将其部署到 AWS EMR 集群进行分布式计算。包含完整的实操步骤、代码示例和故障排除指南。


目录


一、环境准备

1.1 所需软件版本

软件 版本 说明
Windows 10/11 操作系统
JDK 1.8 Hadoop 2.x 推荐版本
IntelliJ IDEA 2023.x 开发 IDE
Hadoop 2.8.5 Hadoop 运行环境
AWS EMR 5.x+ 云端集群服务

1.2 安装步骤

安装 JDK 8
powershell 复制代码
# 检查 Java 版本
java -version
# 输出示例:java version "1.8.0_333"
下载并解压 Hadoop

访问 Hadoop 官网 下载 hadoop-2.8.5.tar.gz,解压到本地目录:

复制代码
E:\hadoop\hadoop-2.8.5
下载 winutils

由于 Windows 原生不支持 Hadoop 的部分功能,需要下载 winutils,将 bin 目录下的文件拷贝到 hadoop-2.8.5/bin 目录中覆盖原文件。


二、创建 Maven 工程

2.1 新建项目

在 IntelliJ IDEA 中创建 Maven 项目:

2.2 配置 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.example</groupId>
    <artifactId>mapreducedemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <hadoop.version>2.8.5</hadoop.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.4</version>
                <configuration>
                    <createDependencyReducedPom>false</createDependencyReducedPom>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                            <transformers>
                                <transformer 
                    implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                                <transformer 
                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.example.WordCount</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

三、编写 WordCount 程序

3.1 创建 Java 类

创建包 com.example 和类 WordCount.java

java 复制代码
package com.example;

import java.io.IOException;
import java.util.StringTokenizer;

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

public class WordCount {

    public static class TokenizerMapper
            extends Mapper<Object, Text, Text, IntWritable> {

        private final static IntWritable one = new IntWritable(1);
        private Text word = new Text();

        public void map(Object key, Text value, Context context
        ) throws IOException, InterruptedException {
            StringTokenizer itr = new StringTokenizer(value.toString());
            while (itr.hasMoreTokens()) {
                word.set(itr.nextToken());
                context.write(word, one);
            }
        }
    }

    public static class IntSumReducer
            extends Reducer<Text, IntWritable, Text, IntWritable> {
        private IntWritable result = new IntWritable();

        public 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);
        }
    }

    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();
        Job job = Job.getInstance(conf, "word count");
        job.setJarByClass(WordCount.class);
        job.setMapperClass(TokenizerMapper.class);
        job.setCombinerClass(IntSumReducer.class);
        job.setReducerClass(IntSumReducer.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);
    }
}

3.2 创建输入文件

在项目根目录创建 demo.txt

复制代码
Hello World
Hello Hadoop
Hello MapReduce
MapReduce is fun
Hadoop is powerful

四、Windows 本地运行调试

4.1 配置运行参数

在 IDEA 中配置运行参数:

4.2 设置环境变量

在 IDEA 的运行配置中设置环境变量:

复制代码
HADOOP_HOME=E:\hadoop\hadoop-2.8.5
PATH=E:\hadoop\hadoop-2.8.5\bin;%PATH%

4.3 常见错误与解决方案

问题:运行时报错

复制代码
Exception in thread "main" java.lang.UnsatisfiedLinkError: 
org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z

解决方案 :确保已正确安装 winutils,并设置了 HADOOP_HOME 环境变量。

4.4 运行成功

运行成功后,输出目录 output 会生成以下文件:

复制代码
output/
├── _SUCCESS
└── part-r-00000

查看 part-r-00000 内容:

复制代码
Hello   3
Hadoop  2
MapReduce   2
World   1
fun     1
is      2
powerful    1

五、打包与命令行测试

5.1 打包项目

bash 复制代码
mvn clean package

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

5.2 命令行测试

powershell 复制代码
# 设置环境变量
set HADOOP_HOME=E:\hadoop\hadoop-2.8.5
set PATH=E:\hadoop\hadoop-2.8.5\bin;%PATH%

# 运行程序
java -jar mapreducedemo-1.0-SNAPSHOT.jar demo.txt output

六、部署到 AWS EMR

6.1 上传文件到 S3

bash 复制代码
# 上传 JAR 包
aws s3 cp target/mapreducedemo-1.0-SNAPSHOT.jar \
    s3://your-bucket/jar/mapreducedemo-1.0-SNAPSHOT.jar

# 上传输入文件
aws s3 cp demo.txt \
    s3://your-bucket/input/demo.txt

6.2 创建 EMR 集群

登录 AWS 控制台,进入 EMR 服务:

6.3 添加 Step

在集群创建过程中或创建后,添加 MapReduce Step:

配置参数

  • Step type: Custom JAR
  • Name: WordCount
  • JAR location : s3://your-bucket/jar/mapreducedemo-1.0-SNAPSHOT.jar
  • Arguments : s3://your-bucket/input/demo.txt s3://your-bucket/output

七、查看运行结果

7.1 等待运行完成

在 EMR 控制台查看 Step 状态:

7.2 查看输出

运行完成后,在 S3 中查看输出文件:

bash 复制代码
# 下载输出文件
aws s3 cp s3://your-bucket/output/part-r-00000 .

# 查看内容
cat part-r-00000

八、MapReduce 执行原理深入解析

8.1 MapReduce 执行流程

#mermaid-svg-coc3shS2JFJCDV6n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-coc3shS2JFJCDV6n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-coc3shS2JFJCDV6n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-coc3shS2JFJCDV6n .error-icon{fill:#552222;}#mermaid-svg-coc3shS2JFJCDV6n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-coc3shS2JFJCDV6n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-coc3shS2JFJCDV6n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-coc3shS2JFJCDV6n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-coc3shS2JFJCDV6n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-coc3shS2JFJCDV6n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-coc3shS2JFJCDV6n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-coc3shS2JFJCDV6n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-coc3shS2JFJCDV6n .marker.cross{stroke:#333333;}#mermaid-svg-coc3shS2JFJCDV6n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-coc3shS2JFJCDV6n p{margin:0;}#mermaid-svg-coc3shS2JFJCDV6n .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-coc3shS2JFJCDV6n .cluster-label text{fill:#333;}#mermaid-svg-coc3shS2JFJCDV6n .cluster-label span{color:#333;}#mermaid-svg-coc3shS2JFJCDV6n .cluster-label span p{background-color:transparent;}#mermaid-svg-coc3shS2JFJCDV6n .label text,#mermaid-svg-coc3shS2JFJCDV6n span{fill:#333;color:#333;}#mermaid-svg-coc3shS2JFJCDV6n .node rect,#mermaid-svg-coc3shS2JFJCDV6n .node circle,#mermaid-svg-coc3shS2JFJCDV6n .node ellipse,#mermaid-svg-coc3shS2JFJCDV6n .node polygon,#mermaid-svg-coc3shS2JFJCDV6n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-coc3shS2JFJCDV6n .rough-node .label text,#mermaid-svg-coc3shS2JFJCDV6n .node .label text,#mermaid-svg-coc3shS2JFJCDV6n .image-shape .label,#mermaid-svg-coc3shS2JFJCDV6n .icon-shape .label{text-anchor:middle;}#mermaid-svg-coc3shS2JFJCDV6n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-coc3shS2JFJCDV6n .rough-node .label,#mermaid-svg-coc3shS2JFJCDV6n .node .label,#mermaid-svg-coc3shS2JFJCDV6n .image-shape .label,#mermaid-svg-coc3shS2JFJCDV6n .icon-shape .label{text-align:center;}#mermaid-svg-coc3shS2JFJCDV6n .node.clickable{cursor:pointer;}#mermaid-svg-coc3shS2JFJCDV6n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-coc3shS2JFJCDV6n .arrowheadPath{fill:#333333;}#mermaid-svg-coc3shS2JFJCDV6n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-coc3shS2JFJCDV6n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-coc3shS2JFJCDV6n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-coc3shS2JFJCDV6n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-coc3shS2JFJCDV6n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-coc3shS2JFJCDV6n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-coc3shS2JFJCDV6n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-coc3shS2JFJCDV6n .cluster text{fill:#333;}#mermaid-svg-coc3shS2JFJCDV6n .cluster span{color:#333;}#mermaid-svg-coc3shS2JFJCDV6n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-coc3shS2JFJCDV6n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-coc3shS2JFJCDV6n rect.text{fill:none;stroke-width:0;}#mermaid-svg-coc3shS2JFJCDV6n .icon-shape,#mermaid-svg-coc3shS2JFJCDV6n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-coc3shS2JFJCDV6n .icon-shape p,#mermaid-svg-coc3shS2JFJCDV6n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-coc3shS2JFJCDV6n .icon-shape .label rect,#mermaid-svg-coc3shS2JFJCDV6n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-coc3shS2JFJCDV6n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-coc3shS2JFJCDV6n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-coc3shS2JFJCDV6n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Shuffle 细节
输入文件
InputFormat
Split 切分
Mapper 阶段
Shuffle 阶段
排序合并
Reducer 阶段
OutputFormat
输出文件
Partition 分区
Sort 排序
Spill 溢写
Merge 合并

8.2 WordCount 执行过程详解

阶段 输入 输出 说明
Input demo.txt <0, "Hello World"> 读取文件,产生键值对
Map <0, "Hello World"> <Hello, 1>, <World, 1> 分词并计数
Combine <Hello, [1,1,1]> <Hello, 3> 本地合并(可选)
Shuffle Map 输出 按 Key 分组 分区、排序、合并
Reduce <Hello, [3]> <Hello, 3> 最终汇总
Output Reduce 输出 part-r-00000 写入输出文件

8.3 Combiner 的作用

Combiner 是一个本地的 Reducer,它可以在 Map 任务结束后对中间结果进行合并,减少网络传输的数据量:

复制代码
没有 Combiner:
  Map1: <Hello, 1>, <Hello, 1> → 传输 2 条记录
  Map2: <Hello, 1> → 传输 1 条记录
  Reduce: 接收 3 条记录

有 Combiner:
  Map1: <Hello, 1>, <Hello, 1> → <Hello, 2> → 传输 1 条记录
  Map2: <Hello, 1> → 传输 1 条记录
  Reduce: 接收 2 条记录

九、性能对比与优化建议

9.1 本地 vs EMR 性能对比

指标 本地运行 EMR 集群
数据规模 小数据集(<1GB) 大数据集(>1GB)
计算节点 1 N(可扩展)
网络开销
启动时间 秒级 分钟级
成本 免费 按小时计费

9.2 优化建议

数据层面

  • 合理设置 Block Size(默认 128MB)
  • 使用 SequenceFile 或 Parquet 格式,减少 I/O
  • 数据预处理,去除无效数据

代码层面

  • 使用 Combiner 减少网络传输
  • 避免在 Mapper/Reducer 中创建大量对象
  • 使用自定义 Writable 类型

集群层面

  • 根据数据量选择合适的实例类型
  • 设置合理的 Map/Reduce 任务数量
  • 配置内存和 CPU 参数

十、常见问题与解决方案

10.1 问题汇总

问题 原因 解决方案
UnsatisfiedLinkError Windows 缺少原生库 安装 winutils
ClassNotFoundException 主类配置错误 检查 mainClass 配置
Output directory already exists 输出目录已存在 删除或修改输出路径
EMR Step 失败 权限不足 检查 S3 权限配置
Could not find or load main class JAR 包未正确打包 使用 shade 插件重新打包
java.net.ConnectException 端口未开放 检查安全组配置
OutOfMemoryError 内存不足 调整 JVM 参数

10.2 调试技巧

  1. 查看日志 :EMR 集群的日志存储在 S3 的 logs 目录中
  2. 本地测试:先在本地运行通过后再部署到云端
  3. 逐步验证:每一步都确认成功后再进行下一步
  4. 启用调试模式 :在运行配置中添加 -Dmapred.job.tracker=local
相关推荐
huainingning1 小时前
微软windows系统官网IPV6临时地址介绍
windows·microsoft·智能路由器
Blossom i5 小时前
Python+spark2.0+Hadoop机器学习与大数据实战第十一章:Python Spark的集成开发环境
大数据·hadoop·spark
.Peter6 小时前
.NET/WPF 程序在部分 Windows 电脑无法保存用户环境变量:使用 DPAPI 实现安全兼容
windows·信息安全·c#·.net·wpf·环境变量·dpapi
码字的特恩6 小时前
微软确认暂不为 Windows 11 加入透明效果自定义功能,建议用户使用第三方工具
人工智能·windows·算法·microsoft·计算机·大模型·编程
神奇小梵7 小时前
安全和开发的需要了解的知识————下载内容的安全,和下载内容如何运行
android·windows·安全·个人开发
zhangfeng11337 小时前
Windows AMD显卡跑PyTorch
人工智能·pytorch·windows
楷哥爱开发7 小时前
如何在 Windows、macOS 和 Linux 上安装 scikit-learn (sklearn)
linux·windows·macos
2603_965148118 小时前
eBay商品数据API:寻找海外仓与价格洼地
大数据·人工智能·windows·python·microsoft
江畔柳前堤17 小时前
HBM:大语言模型时代的「算力血液」——从内存墙到带宽革命的深度拆解
服务器·人工智能·windows·目标检测·语言模型·自然语言处理·软件工程
天天进步20151 天前
UI-TARS 源码解析 #22:二次开发实战:用 UI-TARS 做一个简单的 Windows 自动操作 Agent
windows·ui