MapReduce是分为Map阶段和Reduce阶段,其实提高执行效率就是提高这两个阶段的执行效率
默认情况下Map阶段中Map任务的个数是和数据的InputSplit相关的,InputSplit的个数一般是和Block块是有关联的,所以可以认为Map任务的个数和数据的block块个数有关系,针对Map任务的个数我们一般 是不需要干预的。
如果遇到海量小文件,可以考虑把小文件合并成大文件。使用hadoop提供的两个类型可以解决。
Reduce阶段:默认情况下reduce的个数是1个,所以现在MapReduce任务的压力就集中在Reduce阶段了,如果说数据量比较大的时候,一个reduce任务处理起来肯定是比较慢的, 所以我们可以考虑增加reduce任务的个数,这样就可以实现数据分流了,提高计算效率了。
但是注意了,如果增加Reduce的个数,那肯定是要对数据进行分区的,分区之后,每一个分区的数据会 被一个reduce任务处理。
job.setPartitionerClass 来设置分区类,不过目前我们是没有设置的,框架中是
是有默认值。我们可以通过 job.getPartitionerClass 方法看到默认情况下会使用 HashParttioner 这个分区类。
HashPartitioner的实现
/** * Partition keys by their {@link Object#hashCode()}. */ @InterfaceAudience.Public @InterfaceStability.Stable public class HashPartitioner<K2, V2> implements Partitioner<K2, V2> { public void configure(JobConf job) {} /** Use {@link Object#hashCode()} to partition. */ public int getPartition(K2 key, V2 value, int numReduceTasks) { return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks; } }
map里面每一都会进入这个方法来获取他们所在的分区信息,这里的key就是k2,value就是v2。
起决定性的因素就是 numReduceTasks 的值,这个值默认是1,通过 job.getNumReduceTasks() 可知。所以最终任何值%1 都返回0,那也就意味着他们都在0号分区,也就只有这一个分区。
如何修改为多个分区?
把 numReduceTasks 的数目调大,其实就是增加reduce任务的数,有多个分区就有多少个reduce任务。
增reduce任务是否可以提高任务执行效率?
增加redcue任务个数在一定场景下是可以提高效率的,但是在一些特殊场景下单纯增加reduce任务个数是无法达到质的提升的。
哪种场景下增加reduce任务无法提高执行效率?
何为数据倾斜?
假设我们有一个文件,有1000W条数据,这里面的值主要都是数字,1,2,3,4,5,6,7,8,9,10,我们希望统计出来每个数字出现的次数其实在私底下我们是知道这份数据的大致情况的,这里面这1000w条数据,值为5的数据有910w条左右,剩下的9个数字一共只有90w条,那也就意味着,这份数据中,值为5的数据比较集中,或者说值为5的数据属于倾斜的数据,在这一整份数据中,它占得比重比其他的数据多得多。
如何解决数据倾斜?
- 增加reduce任务个数,这个属于治标不治本,针对倾斜不是太严重的数据是可以解决问题的,针对倾斜严重的数据,这样是解决不了根本问题的
- 把倾斜的数据打散这种可以根治倾斜严重的数据。