hadoop对map-reduce运行框架一共提供了3种实现,在mapred-site.xml中通过"mapreduce.framework.name”这个属性来设置为“classic”、“yarn”或者“local”。
在classic模式中,任务是提交给jobtracker,它的地址通过“mapreduce.jobtracker.address”设置。而在yarn中,任务是提交给resource manager中的applications manager,它的地址是通过“yarn.resourcemanager.address”设置(在yarn-site.xml中)。所以如果想在本地使用mapreduce,那么把mapreduce.framework.name和mapreduce.jobtracker.address都设置成local就行了。如果连hdfs也不想启动,那么就fs.defaultFS也设置成"file:///”。
但是hadoop pipes框架似乎没有在这种情况下做充分的测试,我遇到的问题如下:
1. hadoop pipes在启动C++子进程之前,要写入一个jobTokenPass
word文件。从tokencache中读入一个名为"ShuffleAndJobToken”的token,然后写入该文件中。但是问题是,在local模式下,tokencache中根本就木有这个token嘛。于是在这一步,就会抛异常,导致Application初始化失败。我的做法就是把
byte[] pass
word = jobToken==jobToken.getPass
word();
改成
byte[] pass
word = jobToken==null?"dummy".getBytes():jobToken.getPass
word();
绕过去。
2. 紧接着一个问题是,这个文件是被创建在当前目录的,并且权限是0400。
String localPass
wordFile = new File(".") + Path.SEPARATOR + "jobTokenPass
word";
于是第二次启动Application的时候,它会尝试重写这个文件,但是因为没有写入权限,所以写不了。于是即便是最简单的任务,one map task,one reduce task,也一定会失败。但是在windows下却没有这个问题,因为windows下没有chmod可用啊。
3. 然后就是在实际run那个exe之前,它会用TaskLog.captureOutAndError方法把标准输入输出重定向到特定的文件中。可惜,在local模式下,它生出来的路径是无效的路径。
4.在reduce阶段,application是通过PipesReducer这个类初始化的。当它初始化失败的时候,PipesReducer会把异常直接往外抛,ReduceTask类的runOldReducer方法会抓住这个异常,然后再调用PipesReducer的close方法。但是PipesReducer的close方法是假定application已经初始化完了,于是就调用Application的成员函数去终止它,于是就空指针异常了。
我为什么非要这么运行呢?因为在local模式下,一共就一个jvm,
java部分的代码调试起来要简单很多。