1. map数目的计算方法
hadoop提供了一个设置map个数的参数mapred.map.tasks,我们可以通过这个参数来控制map的个数。但是通过这种方式设置map的个数,并不是每次都有效的。原因是mapred.map.tasks只是一个hadoop的参考数值,最终map的个数,还取决于其他的因素。
为了方便介绍,先来看几个名词:
block_size : hdfs的文件块大小,可以通过参数dfs.block.size设置
total_size : 输入文件整体的大小
input_file_num : 输入文件的个数
上述参数都在Hadoop的conf文件中设置了,使用时可以在自己写的脚本上更改这些参数。
(1)默认map个数
如果不进行任何设置,默认的map个数是和blcok_size相关的。
default_num = total_size / block_size;
1
(2)期望大小
可以通过参数mapred.map.tasks来设置程序员期望的map个数,但是这个个数只有在大于default_num的时候,才会生效。
goal_num = mapred.map.tasks;
1
(3)设置处理的文件大小
可以通过mapred.min.split.size 设置每个task处理的文件大小,但是这个大小只有在大于block_size的时候才会生效。
split_size = max(mapred.min.split.size, block_size);
split_num = total_size / split_size;
1
2
(4)计算的map个数
compute_map_num = min(split_num, max(default_num, goal_num))
1
除了这些配置以外,mapreduce还要遵循一些原则。 mapreduce的每一个map处理的数据是不能跨越文件的,也就是说max_map_num <= input_file_num。 所以,最终的map个数应该为:
final_map_num = min(compute_map_num, input_file_num)
经过以上的分析,在设置map个数的时候,可以简单的总结为以下几点:
(1)如果想增加map个数,则设置mapred.map.tasks 为一个较大的值。
(2)如果想减小map个数,则设置mapred.min.split.size 为一个较大的值。
(3)如果输入中有很多小文件,依然想减少map个数,则需要将小文件merger为大文件,然后使用
2. 简单方式设置想要的map个数
控制Task数及Split大小的相关参数
mapred.map.tasks.x
mapred.min.split.size
abaci.split.optimize.enable
1
2
3
Notes:输入目录文件支持分隔,例如gz压缩问题不支持split。
需求1:
File/Seqence等非Combine的InputFormat
单个Split的大小,尽量在1G( > blkSize,默认256M)
mapred.min.split.size=1073741824 // 1024*1024*1024 = 1,073,741,824
1
如果单文件Size小于1G,SplitSize = 文件大小,不是1G
需求2:
File/Seq等非Combine的InputFormat
单个Split的大小,尽量在30M( < blkSize,默认256M)
abaci.split.optimize.enable=false
mapred.map.tasks= ${总数据量}/30M
1
2
需求3:
File/Seq等非Combine的InputFormat
MapTask数固定为m
abaci.split.optimize.enable=false
mapred.map.tasks=m
1
2
需求4:
CombineInputFormat
单Split(Task)处理不超过1G数据
mapred.max.split.size=1073741824 // 1024*1024*1024 = 1,073,741,824
1
3.注意
第2节的方法实际上是将第一节中的split_num给关闭了,计算最终的map个数时只需要计算:
compute_map_num = max(default_num, goal_num)
1
所以在设置mapred.map.tasks时一定要比default_num大才有效。