关于在eclipse上能运行Map但无法运行Reduce的解决方法

关于在eclipse上能运行Map但无法运行Reduce的解决方法,第1张

今日我在eclipse上运行Map/Reduce框架进行数据分析的时候遇到了一个很奇怪的错误:

一开始我发现运行程序之后也没在控制台报错,也生成了目标目录,但一直出不来统计好的数据文件。

我先通过位置标记输出来判断各个类的加载是否正常,

发现Map是可以正常加载执行的,但是Reduce一直无法加载执行。

然后我通过设置,让其在运行时显示日志信息,再运行。

文末会分享设置显示日志信息的方法。缺岁

这一次伏孙睁便发现了如下的报错:

日志中的报错信息:

java.lang.Exception: org.apache.hadoop.mapreduce.task.reduce.Shuffle$ShuffleError: error in shuffle in localfetcher#1at org.apache.hadoop.mapred.LocalJobRunner$Job.runTasks(LocalJobRunner.java:462)at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:529)Caused by: org.apache.hadoop.mapreduce.task.reduce.Shuffle$ShuffleError: error in shuffle in localfetcher#1at org.apache.hadoop.mapreduce.task.reduce.Shuffle.run(Shuffle.java:134)at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:376)at org.apache.hadoop.mapred.LocalJobRunner$Job$ReduceTaskRunnable.run(LocalJobRunner.java:319)at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)at java.util.concurrent.FutureTask.run(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)at java.lang.Thread.run(Unknown Source)Caused by:(1)]java.io.FileNotFoundException: E:/tmp/hadoop-Alan%20Yang/mapred/local/localRunner/Alan%20Yang/jobcache/job_local214639494_0001/凯尺attempt_local214639494_0001_m_000003_0/output/file.out.indexat org.apache.hadoop.fs.RawLocalFileSystem.open(RawLocalFileSystem.java:200)at org.apache.hadoop.fs.FileSystem.open(FileSystem.java:767)at (2)]org.apache.hadoop.io.SecureIOUtils.openFSDataInputStream(SecureIOUtils.java:156)at org.apache.hadoop.mapred.SpillRecord.<init>(SpillRecord.java:70)at org.apache.hadoop.mapred.SpillRecord.<init>(SpillRecord.java:62)at org.apache.hadoop.mapred.SpillRecord.<init>(SpillRecord.java:57)at org.apache.hadoop.mapreduce.task.reduce.LocalFetcher.copyMapOutput(LocalFetcher.java:124)at org.apache.hadoop.mapreduce.task.reduce.LocalFetcher.doCopy(LocalFetcher.java:102)at org.apache.hadoop.mapreduce.task.reduce.LocalFetcher.run(LocalFetcher.java:85)2017-07-12 16:19:02,616 INFO [org.apache.hadoop.mapreduce.Job] - Job job_local214639494_0001 failed with state FAILED due to: NA2017-07-12 16:19:02,663 INFO [org.apache.hadoop.mapreduce.Job] - Counters: 22File System CountersFILE: Number of bytes read=62223FILE: Number of bytes written=176635984FILE: Number of read operations=0FILE: Number of large read operations=0FILE: Number of write operations=0HDFS: Number of bytes read=898750946HDFS: Number of bytes written=0HDFS: Number of read operations=140HDFS: Number of large read operations=0HDFS: Number of write operations=10Map-Reduce FrameworkMap input records=2629660Map output records=2626091Map output bytes=26260910Map output materialized bytes=31513152Input split bytes=1210Combine input records=0Spilled Records=2626091Failed Shuffles=0Merged Map outputs=0GC time elapsed (ms)=496Total committed heap usage (bytes)=7754743808File Input Format Counters Bytes Read=163038920

按照通常的排错思路,后面的错误往往是前面的错误导致产生的,所以我先入为主的直接去搜索 error in shuffle in localfetcher的解决办法,发现几乎都在说是内存的问题。百般尝试始终是毫无成效。

后来当我往下看的时候发现其实日志给出了大概的错误原因,是路径的问题。这一下子就找到了正确的方向。通过查找资料,发现有的朋友通过修改默认的路径即可解决,我尝试了一下,结果只是换个路径报错而已。这就耐人寻味了,我再自己看了看这条报错信息,里面用到了我的Windows的用户名,但是中间的空格变成了%20,在路径中出现%这意味着什么?配过环境变量的人都知道。我一下子恍然大悟。很有可能是Windows用户名的问题。所以我去修改了Windows本机的用户名,把空格去掉。一下子就解决了!!!

eclipse控制台不显示MapReduce程序日志的解决方法:

使用Hadoop2.6.0,在eclipse下面调试mapreduce程序的时候,控制台不打印程序运行时的日志,而是显示如下信息:

log4j:WARN No appenders could be found for logger (org.apache.[Hadoop]

log4j:WARN Please initialize the log4j system properly.

log4j:WARN [hadoop] See noconfig for more info.

说明没有配置log4j.properties文件。这虽然不影响程序的正常运行,但是看不到日志难免不爽。解决方法:把Hadoop2.6.0的安装目录下面的/etc/hadoop/目录下面的log4j.properties文件拷贝放到MapReduce工程的src目录下面。

一、首先要知道此前提转载若在windows的Eclipse工程中直接启动mapreduc程序,需要先把hadoop集群的配置目录下的xml都拷贝到src目录下,让程序自动读取集群的地址后去进行分布式运行(您也可以自己写java代码去设置job的configuration属性)。若不拷贝,工程中bin目录没有完整的xml配置文件,则windows执行的mapreduce程序全部通过本机的jvm执行,作业名也是带有“local"字眼的作业,如job_local2062122004_0001。这不是真正的分布式运行mapreduce程序。估计得研究org.apache.hadoop.conf.Configuration的源码,反正xml配置文件会影响执行mapreduce使用的文件系统是本机的windows文件系统还是远程的hdfs系统还有影响执行mapreduce的mapper和reducer的是本机的jvm还是集群里面机器的jvm二、本文的结论第一点就是:windows上执行mapreduce,必须打jar包到所有slave节点才能正确分布式运行mapreduce程序。(我有个需求是要windows上触发一个mapreduce分布式运行)第二点就是:Linux上,只需拷贝jar文件到集群master上,执行命令hadoopjarPackage.jarMainClassName即可分布式运行mapreduce程序。第三点就是:推荐使用附一,实现了自动打jar包并上传,分布式执行的mapreduce程序。附一、推荐使用此方法:实现了自动打jar包并上传,分布式执行的mapreduce程序:请先参考博文五篇:Hadoop作业提交分析(一)~~(五)引用博文的附件中EJob.java到你的工程中,然后main中添加如下方法和代码。publicstaticFilecreatePack()throwsIOException{FilejarFile=EJob.createTempJar("bin")ClassLoaderclassLoader=EJob.getClassLoader()Thread.currentThread().setContextClassLoader(classLoader)returnjarFile}在作业启动代码中使用打包:Jobjob=Job.getInstance(conf,"testAnaAction")添加:StringjarPath=createPack().getPath()job.setJar(jarPath)即可实现直接runasjavaapplication在windows跑分布式的mapreduce程序,不用手工上传jar文件。附二、得出结论的测试过程(未有空看书,只能通过愚笨的测试方法得出结论了)一.直接通过windows上Eclipse右击main程序的java文件,然后"runasapplication"或选择hadoop插件"runonhadoop"来触发执行MapReduce程序的测试。1,如果不打jar包到进集群任意linux机器上,它报错如下:[work]2012-06-2515:42:47,360-org.apache.hadoop.mapreduce.Job-10244[main]INFOorg.apache.hadoop.mapreduce.Job-map0%reduce0%[work]2012-06-2515:42:52,223-org.apache.hadoop.mapreduce.Job-15107[main]INFOorg.apache.hadoop.mapreduce.Job-TaskId:attempt_1403517983686_0056_m_000000_0,Status:FAILEDError:java.lang.RuntimeException:java.lang.ClassNotFoundException:ClassbookCount.BookCount$BookCountMappernotfoundatorg.apache.hadoop.conf.Configuration.getClass(Configuration.java:1720)atorg.apache.hadoop.mapreduce.task.JobContextImpl.getMapperClass(JobContextImpl.java:186)atorg.apache.hadoop.mapred.MapTask.runNewMapper(MapTask.java:721)atorg.apache.hadoop.mapred.MapTask.run(MapTask.java:339)atorg.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:162)atjava.security.AccessController.doPrivileged(NativeMethod)atjavax.security.auth.Subject.doAs(Subject.java:415)atorg.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1491)atorg.apache.hadoop.mapred.YarnChild.main(YarnChild.java:157)Causedby:java.lang.ClassNotFoundException:ClassbookCount.BookCount$BookCountMappernotfoundatorg.apache.hadoop.conf.Configuration.getClassByName(Configuration.java:1626)atorg.apache.hadoop.conf.Configuration.getClass(Configuration.java:1718)8more#Error:后重复三次2012-06-2515:44:53,234-org.apache.hadoop.mapreduce.Job-37813[main]INFOorg.apache.hadoop.mapreduce.Job-map100%reduce100%现象就是:报错,无进度,无运行结果。2,拷贝jar包到“只是”集群master的$HADOOP_HOME/share/hadoop/mapreduce/目录上,直接通过windows的eclipse"runasapplication"和通过hadoop插件"runonhadoop"来触发执行,它报错同上。现象就是:报错,无进度,无运行结果。3,拷贝jar包到集群某些slave的$HADOOP_HOME/share/hadoop/mapreduce/目录上,直接通过windows的eclipse"runasapplication"和通过hadoop插件"runonhadoop"来触发执行和报错:Error:java.lang.RuntimeException:java.lang.ClassNotFoundException:ClassbookCount.BookCount$BookCountMappernotfoundatorg.apache.hadoop.conf.Configuration.getClass(Configuration.java:1720)atorg.apache.hadoop.mapreduce.task.JobContextImpl.getMapperClass(JobContextImpl.java:186)和报错:Error:java.lang.RuntimeException:java.lang.ClassNotFoundException:ClassbookCount.BookCount$BookCountReducernotfound现象就是:有报错,但仍然有进度,有运行结果。4,拷贝jar包到集群所有slave的$HADOOP_HOME/share/hadoop/mapreduce/目录上,直接通过windows的eclipse"runasapplication"和通过hadoop插件"runonhadoop"来触发执行:现象就是:无报错,有进度,有运行结果。第一点结论就是:windows上执行mapreduce,必须打jar包到所有slave节点才能正确分布式运行mapreduce程序。二在Linux上的通过以下命令触发MapReduce程序的测试。hadoopjar$HADOOP_HOME/share/hadoop/mapreduce/bookCount.jarbookCount.BookCount1,只拷贝到master,在master上执行。现象就是:无报错,有进度,有运行结果。2,拷贝随便一个slave节点,在slave上执行。现象就是:无报错,有进度,有运行结果。但某些节点上运行会报错如下,且运行结果。:14/06/2516:44:02INFOmapreduce.JobSubmitter:Cleaningupthestagingarea/tmp/hadoop-yarn/staging/hduser/.staging/job_1403517983686_0071Exceptioninthread"main"java.lang.NoSuchFieldError:DEFAULT_MAPREDUCE_APPLICATION_CLASSPATHatorg.apache.hadoop.mapreduce.v2.util.MRApps.setMRFrameworkClasspath(MRApps.java:157)atorg.apache.hadoop.mapreduce.v2.util.MRApps.setClasspath(MRApps.java:198)atorg.apache.hadoop.mapred.YARNRunner.createApplicationSubmissionContext(YARNRunner.java:443)atorg.apache.hadoop.mapred.YARNRunner.submitJob(YARNRunner.java:283)atorg.apache.hadoop.mapreduce.JobSubmitter.submitJobInternal(JobSubmitter.java:415)atorg.apache.hadoop.mapreduce.Job$10.run(Job.java:1268)atorg.apache.hadoop.mapreduce.Job$10.run(Job.java:1265)atjava.security.AccessController.doPrivileged(NativeMethod)atjavax.security.auth.Subject.doAs(Subject.java:415)atorg.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1491)atorg.apache.hadoop.mapreduce.Job.submit(Job.java:1265)atorg.apache.hadoop.mapreduce.Job.waitForCompletion(Job.java:1286)atcom.etrans.anaSpeed.AnaActionMr.run(AnaActionMr.java:207)atorg.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)atcom.etrans.anaSpeed.AnaActionMr.main(AnaActionMr.java:44)atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)atjava.lang.reflect.Method.invoke(Method.java:606)atorg.apache.hadoop.util.RunJar.main(RunJar.java:212)第二点结论就是:Linux上,只需拷贝jar文件到集群master上,执行命令hadoopjarPackage.jarMainClassName即可分布式运行mapreduce程序。

先看一个标准的hbase作为数据读取源和输出目标的样例:

Configuration conf = HBaseConfiguration.create()

Job job = new Job(conf, "job name ")

job.setJarByClass(test.class)

Scan scan = new Scan()

TableMapReduceUtil.initTableMapperJob(inputTable, scan, mapper.class, Writable.class, Writable.class, job)

TableMapReduceUtil.initTableReducerJob(outputTable, reducer.class, job)

job.waitForCompletion(true)

和普通的mr程序不同的是,不再用job.setMapperClass()和job.setReducerClass()来设置mapper和reducer,而用TableMapReduceUtil的initTableMapperJob和initTableReducerJob方法来实现。此处的TableMapReduceUtil是hadoop.hbase.mapreduce包中的,而不是hadoop.hbase.mapred包中的。

数据输入源是hbase的inputTable表,执行mapper.class进行map过程,输出的key/value类型是 ImmutableBytesWritable和Put类型,最后一个参数是作业对象。需要指出的是需要声明一个前丛扫描读入对象scan,进行表扫描读取数据用,其中scan可以配置参数。

数据槐歼输出目标是hbase的outputTable表,输出执行的reduce过程是reducer.class类, *** 作的作业目标是job。与map比缺少输出类型的标注,因为他们不是必要的,看过源代码就知道mapreduce的TableRecordWriter中write(key,value) 方法中,key值是没有用到的,value只能是Put或者Delete两种类型,write方法会自行判断并不用用户指明。

mapper类从hbase读取数据,所以输入的

public class mapper extends TableMapper<KEYOUT, VALUEOUT>{

public void map(Writable key, Writable value, Context context)

throws IOException, InterruptedException {

//mapper逻辑

context.write(key, value)

}

}

mapper继承的是TableMapper类,后边跟的两个泛型参数指定mapper输出的数据类型,该类型必须继承自Writable类,例如可能用到的put和delete就可以。需要注意的是要和initTableMapperJob 方法指定的数据类型一致。该过程会自动从指定hbase表内一行一行读取数据进行处理。

reducer类将数据写入hbase,所以输出的

public class reducer extends TableReducer<KEYIN, VALUEIN, KEYOUT>{

public void reduce(Text key, Iterable<VALUEIN>values, Context context)

throws IOException, InterruptedException {

//reducer逻辑

context.write(null, put or delete)

}

}

reducer继承的是TableReducer类,后边指定三个泛型参数,前两个必须对应map过程的输出key/value类型,第三个是 The type of the output key,write的时候可以把key写成IntWritable什么的都行,它是不必要的。这样reducer输出的数据会自动插入outputTable指定的表内。

TableMapper和TableReducer的本质就是为了简化一下书写代码,因为传入的4个泛型参数里都会有固定的参数类型,所以铅悔冲是Mapper和Reducer的简化版本,本质他们没有任何区别。源码如下:

public abstract class TableMapper<KEYOUT, VALUEOUT>

extends Mapper<ImmutableBytesWritable, Result, KEYOUT, VALUEOUT>{

}

public abstract class TableReducer<KEYIN, VALUEIN, KEYOUT>

extends Reducer<KEYIN, VALUEIN, KEYOUT, Writable>{

}

封装了一层确实方便多了,但也多了很多局限性,就不能在map里写hbase吗?

我他么试了一下午,约5个小时,就想在map里读hdfs写hbase,莫名其妙的各种问题,逻辑上应该没有错,跟着别人的文章做的。最后还是通过IdentityTableReducer这个类实现了,what's a fucking afternoon!

官方对IdentityTableReducer的说明是:Convenience class that simply writes all values (which must be Put or Delete instances) passed to it out to the configured HBase table.

这是一个工具类,将map输出的value(只能是Put或Delete)pass给HBase。看例子:

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.lib.input.FileInputFormat

import org.apache.hadoop.util.GenericOptionsParser

import org.apache.hadoop.hbase.HBaseConfiguration

import org.apache.hadoop.hbase.client.Put

import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil

import org.apache.hadoop.hbase.mapreduce.IdentityTableReducer

public class WordCount

{

public static class TokenizerMapper

extends Mapper<Object, Text, Text, Put>

{

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())

Put putrow = new Put(word.toString().getBytes())

putrow.add("info".getBytes(), "name".getBytes(),"iamvalue".getBytes())

context.write(word, putrow)

}

}

}

public static void main(String[] args) throws Exception

{

Configuration conf = HBaseConfiguration.create()

String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs()

Job job = new Job(conf, "hdfs to hbase")

job.setJarByClass(WordCount.class)

job.setMapperClass(TokenizerMapper.class)

job.setMapOutputKeyClass(Text.class)

job.setMapOutputValueClass(Put.class)//important

FileInputFormat.addInputPath(job, new Path(otherArgs[0]))

TableMapReduceUtil.initTableReducerJob("test", IdentityTableReducer.class, job)

job.setNumReduceTasks(0)

System.exit(job.waitForCompletion(true) ? 0 : 1)

}

}

无论是什么方法吧,总算可以运行了!

MapReduce和HBase结合,似乎是这样一种框架:map读HBase,reduce写HBase。使用IdentityTableReducer就是处于这样一种框架之内。

运行 *** 作HBase的MapReduce程序的第2种方式:HADOOP_CLASSPATH的设置

在我《HBase *** 作》一文中提到了运行 *** 作HBase的MapReduce程序的两种方式,现在说明下另一种方式。

打开hadoop/etc/hadoop/hadoop-env.sh,在设置HADOOP_CLASSPATH的后面添加下面的语句,即将hbase的jar包导入:

for f in /home/laxe/apple/hbase/lib/*.jardo

if [ "$HADOOP_CLASSPATH" ]then

export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$f

else

export HADOOP_CLASSPATH=$f

fi

done

然后就可以用最初的运行MapReduce的方式来运行了。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12390878.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存