您的位置:首页 > 编程语言 > Java开发

在Eclipse上运行Hadoop程序,DistributedCache找不到文件缓存的问题

2014-04-06 22:16 549 查看
2014期李海波同学作品 【原文链接

前一段时间在网上找了一个K-means算法的分布式实现,里面涉及到分布式缓存DistributedCache的问题,我在eclipse中运行MapReduce程序,运行后在命令窗口中明明显示分布式缓存已经建立,但是程序就是读取不到文件,网上各种查找方法,没有解决。
后面我采用一种折中的办法,就是在每个Map或者Reduce中采用FileSystem读取HDFS系统中的文件,将需要的内容放入内存中,程序可以成功运行。但是后来经老师指点,这个读取HDFS文件的方法,在每个Map或者Reduce线程中都会执行一次,对于读取文件比较大或者有很多个线程时,有很明显的弊端。所以下定决心已一定要解决这个问题,下面详细叙述一下问题,以及解决方法。

问题描述
以前运行MapReduce程序都是在Eclipse上运行的,所有不假思索的将这个分布式缓存的文件也在Eclipse下面运行。一个文件加入分布式缓存的代码如下,只有两行程序,但是一定要注意分布式缓存的添加一定要在new Job之前,否则容易出错。

Configuration conf = new Configuration();
    Path vocabularyPath = new Path(
"hdfs://10.104.5.136:9000/user/hadoop/tmp/4-vocabulary/part-r-00000");
    DistributedCache.addCacheFile(vocabularyPath.toUri(), conf); //放在new Job之前,否则读不到CacheFile
      
    Job job = new Job(conf, "GenerateDocVectors");
    job.setJarByClass(GenerateDocVectors.class);
    job.setMapperClass(DocVectorMapper.class);
    job.setMapOutputKeyClass(LongWritable.class);
    job.setMapOutputValueClass(Text.class);
    job.setReducerClass(DocVectorReducer.class);
    job.setOutputKeyClass(NullWritable.class);
    job.setOutputValueClass(DocVector.class);
    FileInputFormat.addInputPath(job, new Path("hdfs://10.104.5.136:9000/user/hadoop/tmp/3-tf-idf"));
     FileOutputFormat.setOutputPath(job, new Path("hdfs://10.104.5.136:9000/user/hadoop/tmp/5-doc-vectors"));
     System.exit(job.waitForCompletion(true) ? 0 : 1);

读取分布式缓存的代码也是网上常用的,只有几行代码,但是需要注意不需要在caches[0].toString前面加上"file://",网上很多地方都说要加上,原因是FIleReader类默认读取的文件系统就是本地文件系统,而不是HDFS文件系统。

@Override
public void setup(Context context) throws IOException {
BufferedReader br = null;
Path[] caches = DistributedCache.getLocalCacheFiles(context.getConfiguration());
if (caches == null || caches.length <= 0) {
System.out.println("No DistributedCache keywords File!");
System.exit(1);
}
System.out.println(caches[0].toString());
br = new BufferedReader(new FileReader(caches[0].toString()));
String line;
while ((line = br.readLine()) != null) {
if (!line.trim().equals("")) {
keywords.add(line.trim());
}
}
br.close();
}

运行后分布式Console命令提示框中显示分布式缓存已经成功创建:

14/04/01 16:28:12 INFO filecache.TrackerDistributedCacheManager: Creating part-r-00000 in /tmp/hadoop-lihaibo/mapred/local/archive/-9064445594102647030_1090122960_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary-work--4639061430523519916
with rwxr-xr-x
14/04/01 16:28:12 INFO filecache.TrackerDistributedCacheManager: Cached hdfs://10.104.5.136:9000/user/hadoop/tmp/4-vocabulary/part-r-00000 as /tmp/hadoop-lihaibo/mapred/local/archive/-9064445594102647030_1090122960_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary/part-r-00000
14/04/01 16:28:12 INFO filecache.TrackerDistributedCacheManager: Cached hdfs://10.104.5.136:9000/user/hadoop/tmp/4-vocabulary/part-r-00000 as /tmp/hadoop-lihaibo/mapred/local/archive/-9064445594102647030_1090122960_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary/part-r-00000

但是读取文件的时候总显示找不到指定缓存文件

14/04/01 16:28:15 WARN mapred.LocalJobRunner: job_local_0001
java.io.FileNotFoundException: file:\tmp\hadoop-lihaibo\mapred\local\archive\-9064445594102647030_1090122960_121196988\10.104.5.136\user\hadoop\tmp\4-vocabulary\part-r-00000 (文件名、目录名或卷标语法不正确。)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.(Unknown Source)
at java.io.FileInputStream.(Unknown Source)
at java.io.FileReader.(Unknown Source)
at cn.edu.sysu.arui.mapred.GenerateDocVectors$DocVectorReducer.setup(GenerateDocVectors.java:80)
at org.apache.hadoop.mapreduce.Reducer.run(Reducer.java:174)
at org.apache.hadoop.mapred.ReduceTask.runNewReducer(ReduceTask.java:649)
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:417)
at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:260)

心理历程
1、起初在网上找了很多地方多说默认读取的是HDFS文件,而分布式缓存实在节点Datanode的本地上,所以需要在所读取的文件前面加上"file://",但是试了,不行。
2、后面网上有创建分布式缓存的链接,能够更加轻松地解决分布式缓存的问题,也按照网上的方式尝试了一遍,还是没有解决。
3、中间看到命令行中显示,分布式缓存已经成功创建,但是读不到,我觉得程序运行完后可能缓存文件会被清除,所以才用调试的方式,在分布式文件创建之后,读取之前设置断点,但是在Hadoop集群上的HDFS文件系统和本地文件系统都找不到这个缓存文件。
4、绝望中用读取HDFS文件的方式来代替分布式缓存,上面说了,效率低下,尤其是在缓存文件比较大或者是Map线程(Reduce线程)比较多的时候,问题解决了,但是心里总感觉不爽。
5、上大数据课的时候问了刘军老师,在老师的指点下重新进行查了一遍错误,偶然间在创建分布式缓存的链接的时候,发现了一个比较奇怪的事情。

14/04/01 17:28:06 INFO filecache.TrackerDistributedCacheManager: Creating part-r-00000 in /tmp/hadoop-lihaibo/mapred/local/archive/6967473064854589526_1260178816_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary-work-4890346733254620063
with rwxr-xr-x
14/04/01 17:28:06 INFO filecache.TrackerDistributedCacheManager: Cached hdfs://10.104.5.136:9000/user/hadoop/tmp/4-vocabulary/part-r-00000#abc as /tmp/hadoop-lihaibo/mapred/local/archive/6967473064854589526_1260178816_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary/part-r-00000
14/04/01 17:28:06 INFO filecache.TrackerDistributedCacheManager: Cached hdfs://10.104.5.136:9000/user/hadoop/tmp/4-vocabulary/part-r-00000#abc as /tmp/hadoop-lihaibo/mapred/local/archive/6967473064854589526_1260178816_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary/part-r-00000
14/04/01 17:28:06 WARN mapred.LocalJobRunner: LocalJobRunner does not support symlinking into current working dir.
14/04/01 17:28:06 INFO mapred.TaskRunner: Creating symlink: /tmp/hadoop-lihaibo/mapred/local/archive/6967473064854589526_1260178816_121196988/10.104.5.136/user/hadoop/tmp/4-vocabulary/part-r-00000 <- D:\tmp\hadoop-lihaibo\mapred\local\localRunner/abc
14/04/01 17:28:06 INFO mapred.JobClient: Cleaning up the staging area file:/tmp/hadoop-lihaibo/mapred/staging/lihaibo1582277947/.staging/job_local_0001

为什么产生缓存文件会只想D盘的一个文件中呢?linux系统哪有D盘,原来问题在于eclipse没有将程序打包成jar,在Hadoop集群上运行,而是自己在本地运行。天啊,终于发现问题在哪儿,话了几天都没搞定的问题终于找到原因了。
解决方法
当然既然Eclipse默认在本地执行,那么解决的方法当然在Eclipse下面打包,将生成的jar包上传到Hadoop中,然后运行hadoop jar命令就可以了,问题解决起来容易,但是找到问题产生的原因很难。

经验教训
1、MapReduce程序最好在Hadoop集群上运行,而不是用Eclipse在本地执行。
2、遇到问题时一定要仔细阅读Console命令提示框中的信息,仔细思考,找出问题的根源。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐