概述
前言:
在之前的笔记中,我们已经成功的关联了eclipse和hadoop,对FileSystem的使用进行了简单了解。
下面就是Hadoop中的重点MapReduce程序的开发。作为MapReduce(以下使用MR来代替)开发中的入门程序WordCount,基本是每个学习MapReduce的同学都必知必会的。有关于WordCount的概念笔者就不再赘述,网上有N多文章讲解。
本次博客主要是记录笔者在Windows环境下使用eclipse进行WordCount程序编写过程中所遇到的问题及解决方案。
准备工作:
* Windows环境下Eclipse工具的准备(需要使用插件关联hadoop,更多细节请参考笔者另一篇文章https://blog.csdn.net/qq_26323323/article/details/82936098 )
* 创建maven项目,命名为hadoop,将Linux环境下hadoop的配置文件core-site.xml/mapred-site.xml/hdfs-site.xml/yarn-site.xml放入hadoop/src/main/resources中(主要是因为MR程序需要加载这些配置文件中的配置内容)
* 在hadoop/src/main/resources中创建log4j.properties文件,内容如下
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
注意:之所以要创建该文件,是因为在eclipse中启动MR程序时,默认是没有日志的,我们加载log4j的配置后,root设置为DEBUG级别,那么程序的每一步操作我们都可以通过日志来观察到,有利于我们定位问题
* 使用用户hxw(笔者)来启动hadoop
HADOOP_HOME/sbin/start-dfs.sh
HADOOP_HOME/sbin/start-yarn.sh
1.WordCount程序的编写
具体内容如下,笔者不再详述
package hadoop.mr;
import java.io.IOException;
import java.net.URI;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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 WCMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
private final static IntWritable ONE = new IntWritable(1);
private Text word = new Text();
/**
* map程序,进行切割转换
*/
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
throws IOException, InterruptedException {
// 1.解析value为token,默认会按照空格进行分割
StringTokenizer token = new StringTokenizer(value.toString());
while(token.hasMoreTokens()){
// 2.将分割后的字符放入Word
word.set(token.nextToken());
// 3.输出k-v格式 类似(hadoop,1)
context.write(word, ONE);
}
}
}
public static class WCReduce extends Reducer<Text, IntWritable, Text, IntWritable>{
private IntWritable result = new IntWritable();
/**
* reduce程序,对map的结果进行合并
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values,
Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
// 1.计算总和
int sum = 0;
for (IntWritable intWritable : values) {
sum += intWritable.get();
}
result.set(sum);
// 2.输出结果
context.write(key, result);
}
}
private static String INPUT_PATH = "/user/hadoop/mapreduce/input/";
private static String OUTPUT_PATH = "/user/hadoop/mapreduce/output/";
private static String HDFS_URI = "hdfs://hadoop:9000";// 对应于core-site.xml中的FS.default
public static void main(String[] args) {
try {
// 1.如果已经有output_path,则先进行删除
deleteOutputFile(OUTPUT_PATH);
// 2.创建job,设置基本属性
Job job = Job.getInstance();
job.setJarByClass(WordCount.class);
job.setJobName("wordcount");
// 3.设置Mapper、Reducer
job.setMapperClass(WCMapper.class);
job.setReducerClass(WCReduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 4.设置输入路径和输出路径
FileInputFormat.addInputPath(job, new Path(INPUT_PATH));
FileOutputFormat.setOutputPath(job, new Path(OUTPUT_PATH));
// 5.执行,执行完成后退出程序
System.exit(job.waitForCompletion(true) ? 0 : 1);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
static void deleteOutputFile(String path) throws Exception{
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(new URI(HDFS_URI),conf,"hxw");
if(fs.exists(new Path(path))){
fs.delete(new Path(path),true);
}
}
}
2.遇到的问题汇总
1)访问HDFS无权限
报错内容一般如下:
org.apache.hadoop.security.AccessControlException: Permission denied: user=root, access=WRITE, inode="":nutch:supergroup:rwxr-xr-x
报错原因:主要是由于HDFS的文件系统都是有用户和权限的,如果当前用户无权限则在使用该文件或文件夹的时候会报错。
解决方案:
* 使用hdfs dfs -chmod 命令来修改相关文件或文件夹权限;
* 如果在测试环境,用户不想这么麻烦来修改权限的话,也可使用配置来禁用hdfs的权限管理,可以在hdfs-site.xml中配置以下内容
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
2)运行过程中,无报错无日志,在http://hadoop:8088 界面中也无任务进度
笔者在运行的过程中,比较烦恼的一件事就是,运行的时候没有任何报错,任务调度界面中也没有任务显示
将项目打成jar包放入Linux环境下,也是可以运行的,很奇怪。
后来,就添加了log4j.properties文件,将root设置为DEBUG级别(内容如上所示),就看到了其中的报错。
所以,我们在运行项目的时候,一定要添加日志文件
3)创建对ResourceManager连接的时候报错
DEBUG [org.apache.hadoop.ipc.Client] - closing ipc connection to 0.0.0.0/0.0.0.0:8032: Connection refused: no further information
java.net.ConnectException: Connection refused: no further information
报错原因:看报错信息,我们知道是在创建对0.0.0.0:8032的Connection时候失败。为什么会失败?应该是无法连接到0.0.0.0这个IP。我们没有在配置文件中配置这个IP和端口,那么这个应该是默认配置。我们去hadoop官网的core-default.xml、yarn-default.xml等默认配置文件进行查看的时候,发现在yarn-site.xml中发现以下内容
yarn.resourcemanager.hostname 0.0.0.0 The hostname of the RM.
yarn.resourcemanager.address ${yarn.resourcemanager.hostname}:8032
那么可以确定这个IP:port是对ResourceManager的连接失败
我们知道ResourceManager负责集群的资源分配,所有NodeManager都需要与ResourceManager进行通信交换信息,yarn.resourcemanager.hostname默认为0.0.0.0,我们将这个内容修改为hadoop,对应着当前本机地址即可
解决方案:在yarn-site.xml中添加
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop</value>
</property>
4)no job control
报错信息如下所示:
Exception message: /bin/bash: line 0: fg: no job control
Stack trace: ExitCodeException exitCode=1: /bin/bash: line 0: fg: no job control
at org.apache.hadoop.util.Shell.runCommand(Shell.java:545)
at org.apache.hadoop.util.Shell.run(Shell.java:456)
...
报错原因:由于我们使用Windows平台进行开发并添加MR任务,而hadoop部署在Linux平台上,故针对跨平台的job会报该错
解决方案:在mapred-site.xml中添加以下配置
设置为job提交允许跨平台
<property>
<name>mapreduce.app-submission.cross-platform</name>
<value>true</value>
</property>
5)ClassNotFoundException
Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class hadoop.mr.WordCount$WCMapper not found
at org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2195)
at org.apache.hadoop.mapreduce.task.JobContextImpl.getMapperClass(JobContextImpl.java:186)
...
报错原因:这个还是比较难解释的,需要对hadoop的运行原理有一定的了解。具体可参考这篇文章 https://blog.csdn.net/qq_19648191/article/details/56684268
解决方案:在core-site.xml中设置如下配置:
<property>
<name>mapred.jar</name>
<value>C:/Users/lucky/Desktop/wc.jar</value>
</property>
然后每次运行WordCount任务的时候,先将当前项目导出为一个jar包,命名为wc.jar,然后位置也要与我们配置的位置一致,这样再运行的时候就不会报错了
最后
以上就是坚定香水为你收集整理的MapReduce之WordCount程序详解及常见错误汇总的全部内容,希望文章能够帮你解决MapReduce之WordCount程序详解及常见错误汇总所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复