前言
在MapReduce开发中,本地IDEA环境编写和调试代码只是第一步,将程序打包并部署到Hadoop集群运行才是真正的生产实践。本文将手把手演示两种打包方式:轻量级打包(仅代码)和胖包打包(含依赖),并配合大量截图,确保每一步都清晰可见。
一、准备工作
1.1 项目结构确认
确保你的MapReduce项目结构如下:
MapReduceDemo/ ├── pom.xml # Maven配置 └── src/main/java/com/lyh/mapreduce/wordcount/ ├── WordCountMapper.java # Mapper类 ├── WordCountReducer.java # Reducer类 └── WordCountRunner.java # Driver驱动类(入口)1.2 核心依赖配置(pom.xml)
<<dependencies><!-- Hadoop客户端依赖 --><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>3.1.3</version></dependency><!-- 单元测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.30</version></dependency></dependencies>关键说明:
hadoop-client是核心依赖,包含HDFS、MapReduce、YARN的所有API。
二、方式一:轻量级打包(仅项目代码)
2.1 适用场景
| 场景 | 说明 |
|---|---|
| 集群已有Hadoop环境 | 服务器上已安装Hadoop,所有依赖都在集群中 |
| jar包体积小 | 仅包含你的代码,通常几十KB到几百KB |
| 传输速度快 | 适合频繁调试、快速迭代 |
2.2 打包步骤详解
步骤1:编译项目
点击IDEA顶部菜单栏的Build → Build Project(或按Ctrl+F9),确保代码无编译错误。
步骤2:执行Maven打包
点击右侧Maven工具栏,展开Lifecycle,双击package:
或者在Terminal中执行命令:
mvn clean package
步骤3:查看生成的jar包
打包完成后,在项目的target目录下会生成jar包:
target/ ├── MapReduceDemo-1.0-SNAPSHOT.jar # 主jar包(轻量级) ├── original-MapReduceDemo-1.0-SNAPSHOT.jar # 原始jar(可选) └── classes/ # 编译后的class文件jar包大小特征:通常只有几十KB,因为只包含项目编译后的class文件,不包含任何依赖。
2.3 验证jar包内容
用压缩工具打开jar包,确认只包含自己的代码:
META-INF/ ├── MANIFEST.MF com/ └── lyh/ └── mapreduce/ └── wordcount/ ├── WordCountMapper.class ├── WordCountReducer.class └── WordCountRunner.class注意:如果jar包里没有依赖项,但集群Hadoop版本与你的pom.xml一致,可以直接运行。
三、方式二:胖包打包(含所有依赖)
3.1 适用场景
| 场景 | 说明 |
|---|---|
| 集群缺少某些依赖 | 如使用了第三方库(Guava、FastJSON等) |
| Hadoop版本不一致 | 开发环境与集群Hadoop版本不同 |
| 独立运行 | 需要在无Hadoop环境的服务器上运行 |
3.2 打包步骤详解
步骤1:先执行方式一的编译(必须)
必须先执行mvn clean package,确保代码编译通过,生成target目录。
步骤2:打开Project Structure
点击顶部菜单File → Project Structure(或按Ctrl+Alt+Shift+S):
步骤3:创建Artifacts
- 选择左侧Artifacts
- 点击上方+按钮
- 选择JAR → From modules with dependencies…
步骤4:选择主类(Main Class)
在弹出的对话框中:
| 配置项 | 说明 | 操作 |
|---|---|---|
| Module | 选择你的项目模块 | 默认即可 |
| Main Class | 选择Driver入口类 | 点击右侧文件夹图标,选择WordCountRunner |
| JAR files from libraries | 依赖处理方式 | 选择extract to the target JAR(提取到jar中) |
关键选择:
extract to the target JAR会将所有依赖解压后合并到一个jar中,形成"胖包"。
步骤5:确认配置
点击OK后,Artifacts列表中会出现新配置:
名称: MapReduceDemo:jar 类型: JAR 输出路径: .../out/artifacts/MapReduceDemo_jar步骤6:构建Artifacts
点击顶部菜单Build → Build Artifacts… → MapReduceDemo:jar → Build:
构建完成后,在out/artifacts/MapReduceDemo_jar/目录下生成胖包:
out/artifacts/MapReduceDemo_jar/ └── MapReduceDemo.jar # 胖包,包含所有依赖jar包大小特征:通常几十MB,因为包含了所有Maven依赖。
3.3 两种打包方式对比
| 维度 | 方式一:轻量级 | 方式二:胖包 |
|---|---|---|
| jar包大小 | 几十KB | 几十MB |
| 包含内容 | 仅项目代码 | 项目代码 + 所有依赖 |
| 集群要求 | 必须有Hadoop环境 | 可独立运行 |
| 传输时间 | 秒级 | 分钟级(取决于网速) |
| 适用场景 | 日常调试、集群环境稳定 | 依赖特殊、环境不一致 |
| 构建方式 | mvn package | Artifacts → Build |
四、上传jar包到集群
4.1 使用MobaXterm上传(推荐)
操作步骤:
- 打开MobaXterm,连接到你的Hadoop服务器(如hadoop102)
- 左侧本地目录找到生成的jar包
- 右侧远程目录选择
/opt/module/hadoop-3.1.3/(或你习惯的目录) - 拖拽jar包到右侧,或右键点击上传
4.2 使用命令行上传
# 使用scp命令(Linux/Mac)scpMapReduceDemo.jar atguigu@hadoop101:/opt/module/hadoop-3.1.3/# 使用rz命令(需先安装lrzsz)# 在服务器上执行 rz,然后选择本地文件五、集群运行jar包
5.1 启动Hadoop集群
# 在hadoop102上执行sbin/start-dfs.sh# 在hadoop103上执行sbin/start-yarn.sh# 验证jps# 应看到: NameNode, DataNode, ResourceManager, NodeManager, JobHistoryServer5.2 准备输入数据
# 创建HDFS输入目录hadoop fs-mkdir-p/input# 上传测试数据hadoop fs-putword.txt /input/# 查看hadoop fs-ls/input5.3 执行MapReduce作业
基本命令格式:
hadoop jar<jar包路径><主类全限定名><输入路径><输出路径>实际执行:
cd/opt/module/hadoop-3.1.3/# 方式一:轻量级jar(集群有Hadoop环境)hadoop jar target/MapReduceDemo-1.0-SNAPSHOT.jar\com.lyh.mapreduce.wordcount.WordCountRunner\/input /output# 方式二:胖包jar(含所有依赖)hadoop jar out/artifacts/MapReduceDemo_jar/MapReduceDemo.jar\com.lyh.mapreduce.wordcount.WordCountRunner\/input /output5.4 查看运行结果
# 查看输出目录hadoop fs-ls/output# 查看结果文件hadoop fs-cat/output/part-r-00000预期输出:
hadoop 1 hello 4 mapreduce 1 world 1 yarn 1六、YARN Web UI监控任务
6.1 访问YARN界面
浏览器打开:http://hadoop102:8088
6.2 查看任务状态
| 状态 | 说明 |
|---|---|
| ACCEPTED | 任务已提交,等待资源分配 |
| RUNNING | 正在运行 |
| FINISHED | 已完成 |
| FAILED | 失败 |
| KILLED | 被终止 |
点击Application ID可查看详细日志和进度。
七、常见问题与解决方案
7.1 问题一:ClassNotFoundException
报错:
Exception in thread "main" java.lang.ClassNotFoundException: com.lyh.mapreduce.wordcount.WordCountRunner原因:
- 主类名写错
- jar包中没有包含主类
解决:
# 检查jar包内容jar tf MapReduceDemo.jar|grepWordCountRunner# 确认主类全限定名正确hadoop jar MapReduceDemo.jar com.lyh.mapreduce.wordcount.WordCountRunner /input /output7.2 问题二:输出目录已存在
报错:
org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://hadoop102:8020/output already exists解决:
# 删除旧输出目录hadoop fs-rm-r/output# 或者更换新路径hadoop jar MapReduceDemo.jar com.lyh.mapreduce.wordcount.WordCountRunner /input /output27.3 问题三:依赖缺失(轻量级jar在集群运行时报错)
报错:
java.lang.NoClassDefFoundError: com/google/common/base/Preconditions原因:使用了Guava等第三方库,但集群没有
解决:
- 改用方式二胖包打包,包含所有依赖
- 或将缺失的jar包上传到集群的
$HADOOP_HOME/share/hadoop/common/lib/
7.4 问题四:权限不足
报错:
org.apache.hadoop.security.AccessControlException: Permission denied: user=xxx, access=WRITE, inode="/output"解决:
# 修改HDFS目录权限hadoop fs-chmod777/# 或者在代码中指定用户FileSystem fs=FileSystem.get(new URI("hdfs://hadoop102:8020"), conf,"atguigu");八、核心知识点总结
| 主题 | 要点 |
|---|---|
| 轻量级打包 | mvn package,仅代码,依赖集群环境 |
| 胖包打包 | Artifacts → From modules with dependencies,含所有依赖 |
| 主类选择 | 必须是Driver类(含main方法),全限定名 |
| 上传工具 | Xftp拖拽、scp命令、rz命令 |
| 运行命令 | hadoop jar <jar> <主类> <输入> <输出> |
| 输出目录 | 必须不存在,否则报错 |
| 监控方式 | YARN Web UI:http://<<ResourceManager>:8088 |
九、完整流程图
IDEA编写代码 → 本地调试通过 → 选择打包方式 ↓ ┌───────────────┴───────────────┐ ↓ ↓ 方式一:mvn package 方式二:Artifacts (轻量级,仅代码) (胖包,含依赖) ↓ ↓ target/*.jar out/artifacts/*.jar └───────────────┬───────────────┘ ↓ Xftp上传到集群 ↓ hadoop jar 执行 ↓ YARN监控任务状态 ↓ 查看HDFS输出结果