提高Hadoop的mapreduce job效率笔记(4)

Hadoop的mapreduce作业通常有如下描述时,会不够高效,如下笔记 :

在tasktracker进程中加入如下配置:-verbose:gc -XX:+PrintGCDetails,然后tasktrakcer就会在运行过程中将GC的detail信息打印到log中,根据log观察,如果能够看到jvm花了很多的时间来做垃圾回收,那么通常,程序中new 了太多的不必要的对象。

在自己的源代码中grep一下“new Text”或者“new IntWritable”,如果在某些循环中找到这样的代码,或者mapper或者reducer中找到这样的代码,通常代码就不够高效。

以上tips在tasks被限制在内存中时通常都非常有效。

对于mapredcue的新手来说,常常会犯这样的一个错误,在自己的程序中大量的new Writable对象。尤其是在mapper函数或者reducer函数中。例如,有些人可能会这样来实现wordcunt:

public void map(...) {

...

for (String word : words) {

output.collect(new Text(word), new IntWritable(1));

}

}

这种实现会造成:非常非常多的临时对象被分配内存。

这样会造成jvm花费很多的时间来进行垃圾回收。正确的做法是:

class MyMapper ... {

Text wordText = new Text();

IntWritable ne = new IntWritable(1);

public void map(...) {

...

for (String word : words) {

wordText.set(word);

output.collect(word, one);

}

}

}

这就是说,在mapreduce中,Writable对象是可重用的,其实这也是hadoop中为什么会使用

writable对象(如Text,IntWritable等),而不是采用原声的java

对应对象的原因。

测试对比:

当把wordcount的代码修改成以上的样子,job的运行时间并没有太大的改变,但是这是因为在配置中默认设定了每个task的heap size的最大为1GB,所以GC在jvm的内存占用没有到一定阈值的时候根本就没有运行。但是,如果将heap size修改为200MB,那么原本8分30秒能完成的作业,变成了17分钟才能完成。所以,在hadoop的mapreduce代码书写的时候,注意这样的一些小技巧 ,是非常有用的。

更多Hadoop相关信息见Hadoop 专题页面 ?tid=13

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/2ff53daaf1561f3621c2eed25f4effcd.html