Hadoop老项目运行问题

概述

当你在运行一个Maven老项目时往往会出现各种错误而导致无法运行,本博文以一个老的Hadoop项目为例介绍无法运行的原因以及解决方案。

原项目链接

rathboma的项目

错误原因

环境问题

老项目无法运行的很大一部分原因是环境问题,比如我的PC安装的java环境为JDK16(现在最高版本为JDK17),是具备运行运行java程序的能力的。

image-20211008110635985

但是当我运行项目时,编辑器将会提示如下错误

image-20211008111220806

看来还是缺少项目运行所需的必要jar包,从下图的项目结构中也可以看出jdk.tools-1.6.jar包处于丢失状态,没找到相应的路径,而这个包本应该是由java库来提供,但是我明明已经配置了java环境,却还是出错了,导致这一结果原因是:

Java SE 9.0于2017年9月21日发布。JDK 9的核心变化就是引入了一种新的Java编程组件,也就是模块,按照Oracle的说法,它是一个可命名的、自描述的代码和数据集合。模块化所带来的其中一个变化包括从Java运行时镜像中移除了rt.jartools.jar

image-20211009160328585

到这便可得出结论,我的JDK版本太高了

依赖问题

当我在导入依赖时,Maven将会自动加载其所需的其他依赖包,但是不会总成功进行,就如上面的环境问题,本地环境根本就没有提供这个jar包,Maven是不可能凭空捏造的,只会提示找不到,所以这里有两个选项,要么降低JDK版本,要么使用其他依赖摆脱掉jdk.tool-1.6.jar,或者这个项目也可以通过升级依赖hadoop-client3.3.1来解决这个问题。

解决方案

Tip

如果你不想了解问题具体是怎么解决的,仅仅想快速上手让项目跑起来,那么你可以直接前往下面的项目运行部分

更换JDK版本

其实不太建议随意更换JDK版本,因为一旦更改,所有与JDK有关的应用和项目都要进行修改,包括IDEA或Eclipse的java编译器版本和项目文件指定的编译器版本,这些都要全部修改一遍,非常繁琐,如果实在想换,那么建议使用JDK8(别名jdk1.8),兼容性比较好。

这里提供了JDK8的官方地址,有需要的可以下载。

更新或更换依赖

出现报错的来自下面这个依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.0.0-mr1-cdh4.3.1</version>
</dependency>

错误信息显示如下图,表明hadoop-annotaions.jar找不到jdk.tools-1.6.jar

image-20211010170602768

考虑到这个项目发自2012年,hadoop-client的版本更新或许已经修复这个问题了,可以尝试一下这个方案。

如下图所示,把hadoop-client升级成3.3.1后,这个问题已经被修复了

image-20211010171233875

另外也可以不使用这个报错的依赖,改用其他依赖,如下面的依赖也可以解决这个问题,让项目得以运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--hadoop-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-jobclient</artifactId>
<version>3.3.0</version>
</dependency>
<!--log-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.1</version>
</dependency>

项目运行

对于大部分使用者都会把Hadoop安装在远程服务器上或者是虚拟机中,因此这里有两种运行方式

  • 远程运行:把项目上传至远程服务器或虚拟机中运行
  • 本地运行:通过在本地模拟出Hadoop的运行环境,可以让项目直接在Windows上运行

两种方式各有优劣,前者能够较为简单的运行项目,但不方便调试,而后者可以更方便的对代码进行调试,但环境搭建较为复杂。

远程运行

准备工作

在运行项目之前,必须具备以下条件(版本可自行选择)

  • JDK1.8已安装
  • Hadoop3.2.2集群已搭建好
  • Maven3.8.3已安装

如果以上环境没有准备完整,请搜索相关教程配置完毕后在进行下面步骤。

项目调整

把项目从Github上下载下来,然后需要对其中的内容进行更改,以适配上边准备好的环境。

使用IDEA或Eclipse打开项目(当然你也可以在服务器上对项目进行操作,如果你不嫌麻烦的话),删除src目录下的测试用文件夹test,以及pom.xml文件中与测试有关的所有依赖TEST DEPENDENCIES,需要删除的部分见下图

image-20211010203633657

删除完成后对应的项目目录结构及项目依赖见下图

image-20211010203937700

pom.xml文件中的hadoop-client依赖升级至3.3.1,同时把< scope>provided< /scope>字段删除

image-20211010204203641

进入RawMapreduce这个类,在main函数中,修改四个路径的参数如下图,其中前两个路径需要你自己去创建,并把输入文件放在相应目录中,如文件transactions.txt应该放在/user/path/transactions/目录中,而文件users.txt应该放在/user/path/users/目录中,而最后两个路径/user/path/staging/user/path/output不需要你创建,Hadoop将会自动生成,你也可以创建其他的目录,但是这四个Path也需要做相应的修改。

image-20211010205144501

如果你不知道如何在HDFS中创建目录、上传文件,那么你需要学习一下HDFS操作

你也可以不设置四个Path的参数,仅在执行项目时手动输入参数,不过我相信你试过几次后就会放弃这样做。

至此项目已经修改完毕,将修改后的项目上传至远程服务器或虚拟机中,之后进入该项目的根目录,然后执行 mvn package assembly:single命令对项目进行打包

image-20211010211059327

依赖下载可能会花费一点时间,打包完成之后将会在当前目录产生target目录,之后进入target目录

image-20211010211309116

target目录中可以看到有两个jar包,只有带有依赖的jar包才能运行

image-20211010211610022

在启动项目之前,你需要先执行以下命令来分别启动HDFS和YARN,前者是Hadoop文件管理系统,后者是Hadoop的资源管理器

1
2
root@master:/home/java-mapreduce/target# start.dfs.sh
root@master:/home/java-mapreduce/target# start.yarn.sh

启动后执行jps命令应该会看到如下结果

1
2
3
4
5
6
7
8
root@master:/home/java-mapreduce/target# jps
91537 NameNode
13921 DataNode
92005 SecondaryNameNode
103382 Jps
99224 NodeManager
98956 ResourceManager
root@master:/home/java-mapreduce/target#

到这你就可以执行刚才打包得到的jar包了,执行以下命令启动项目

1
root@master:/home/java-mapreduce/target# hadoop jar java-mapreduce-1.0-SNAPSHOT-jar-with-dependencies.jar

如果启动没有报错,执行结果见下图

image-20211010212753427

这时你已经可以在浏览器中前往master:9870这个地址查看输出的文件,可直接下载至本地。

master是我搭建的Hadoop名称节点的主机名,如果你想在Windows上访问master:9870,你需要在C:\Windows\System32\drivers\etc\路径下的hosts文件末尾中添加远程服务器ip 主机名,也可以直接把master替换成IP地址,IP地址可通过ifconfig查看。

image-20211010213539518

image-20211010213645038

本地运行

准备工作

  • JDK1.8已安装(远程服务器或虚拟机)
  • Hadoop3.2.2集群已搭建好(远程服务器或虚拟机)
  • JDK16已安装(本地Windows)
  • Maven3.8.2已安装(本地Windows)

在以上环境配置完成后,还需要在Windows上额外安装winutils来虚拟出Hadoop的运行环境。

Winutils

如下图winutils有许多版本可供选择,请选择一个最接近你Hadoop版本的选项下载,如我的远程服务器上的Hadoop版本为3.2.2,那么我下载了winutils的3.2.2版本。

image-20211012194704785

下载后放置在你能找到的路径下,然后配置环境变量,新建环境变量,变量名为HADOOP_HOME,路径为你下载的文件夹存放的位置,之后在Path中添加环境变量,如下图

image-20211012195023527

image-20211012195515829

更改Hosts

如果你想通过主机名直接访问远程服务器,需要在C:\Windows\System32\drivers\etc\这个路径下的hosts文件末尾添加远程服务器ip 主机名,这条语句的作用是把服务器的主机名映射成ip地址,可以方便后续访问

image-20211012200053982

项目调整

使用IDEA或Eclipse打开项目,删除src目录下的测试用文件夹test,删除pom.xml文件中与测试有关的所有依赖TEST DEPENDENCIES,并且升级hadoop-client依赖至3.3.1版本,额外还需添加slf4j-log4j12依赖,最终结果见下图

image-20211012200735650

为了让项目运行时把日志输出在控制台上,需要在src目录下创建resources目录,并添加log4j.properties文件,该文件可以从服务器的Hadoop安装文件中找到

image-20211012201311513

image-20211012201402871

进入RawMapreduce这个类,在main函数中,修改四个路径的参数如下图,其中前两个路径需要你自己服务器上创建,并把输入文件放在相应目录中,如文件transactions.txt应该放在/user/path/transactions/目录中,而文件users.txt应该放在/user/path/users/目录中,而最后两个路径/user/path/staging/user/path/output不需要你创建,Hadoop将会自动生成,你也可以创建其他的目录,但是这四个Path也需要做相应的修改。

image-20211012202042420

这里的参数和远程运行有些许不同,是因为本地的机器并不知道Hadoop资源文件的具体位置,因此需要手动指明ip地址和端口号,而前面已经对主机号和ip地址之间进行了映射处理,这里就可以直接使用主机名了。

同样的,如果你不知道如何在HDFS中创建目录、上传文件,那么你需要学习一下HDFS操作

由于我的JDK版本过高,出现了错误: 不支持发行版本 5的问题,可以在pom.xml文件中指定编译版本

image-20211012203018192

image-20211012203056265

项目运行

在运行项目前,需要先执行以下命令来启动远程服务器上的HDFS

1
root@master:/home/java-mapreduce/target# start.dfs.sh

启动后执行jps命令应该会看到如下结果

1
2
3
4
5
6
root@master:/opt/hadoop-3.2.2/etc/hadoop# jps
155603 NameNode
13921 DataNode
156100 SecondaryNameNode
161208 Jps
root@master:/opt/hadoop-3.2.2/etc/hadoop#

到这你就可以在IDEA或Eclipse上启动项目了,如果成功运行,将会看到如下日志

image-20211012203838566

这时你已经可以在浏览器中前往master:9870这个地址查看输出的文件,可直接下载至本地。

完整项目文件

下面提供了完整的项目文件,如果项目调整遇到问题可以下载以供参考