怎样才能让程序花费的时间最短?Hadoop 是分布式处理系统,可以从两方面进行入手:控制任务的处理数量,使之均衡分布在每个reduce上,不会使哪个任务因为数据量多大而使用过长的时间;增加reduce到一定的数量。
另外的制约因素是tasktracker的负载,一个tasktracker能同时运行多少个map任务,是由 mapred.taskertracker.map.tasks.maximun 属性控制,默认是2个任务。能同时运行多少个reduce任务数是由mapred.tasktracker.reduce.task.maximun属性所控制,默认也是2.
在一个taskertracker 上同时运行的任务数取决于一台机器有多少个处理器,由于mapreduce作业通常是I/O-bound(I/O密集型,cpu通常要等硬盘/内存的读写),因此设置任务数大于处理器数有一定的道理。
1. map的数量
map的数量跟输入的文件大小和个数有关系,可以通过set dfs.block.size 来查看集群设置的文件块大小:
hive> set dfs.block.size;
dfs.block.size=134217728
如果你输入一个文件file1 大小为450M,hdfs 会把它分成4个块,3个128M的和一个66M的文件块,map的数量就是4。
如果你输入4个文件f 大小分别为10M,20M,100M,140M,则hdfs就会把其分成5个文件块:10,20,100,128,12。
map数不是越多越好,如果输入的文件都是小文件,远小于128M,那么每一个文件都会被当作一个map进行处理,map任务启动和初始化时间会大于逻辑处理处理的时间,那么会造成资源的浪费,而且可同时执行的map数是受限制的,只能分批执行。
map处理文件的大小也不是越接近128M越好,同时要根据这个文件记录的数量进行评估,比如文件只有一列,但有几千万行,用一个map来处理是比较费时的。根据实际情况,控制map数量要遵循两个原则: 使大数据量利用合适的map数,使单个map任务处理合适的数据量。
如何合并小文件,减少map数量?
假如有一个SQL任务:
Select count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04’;
该任务的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04
一共有194个文件,其中有很多文件远小于128M,总共9个G大小,正常会运行194个map任务
Map总共消耗的计算资源: SLOTS_MILLIS_MAPS= 623,020
我通过以下方法在map执行前合并小文件,减小map数:
set mapred.max.split.size = 100000000; ---每个map最大输入的大小
set mapred.min.split.size.per.node = 100000000;---一个节点上split至少的大小,决定了跨多个datanode 上的文件是否需要合并
set mapred.min.split.size.per.rack = 100000000; ---一个交换机下split至少的大小,决定了多个交换机上的文件是否需要合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;---执行map前进行小文件的合并
再执行以上的语句,用了74个map任务, map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
对于这个简单的SQL任务,执行时间差不多,但节省了一半的计算资源。
前面三个参数确定合并文件块的大小,大于文件块的大小128M的,按照128来划分,小于128,大于100的,按照100来划分,把那些小于100(包括小文件和大文件划分剩下的)进行合并,最终得到了74块。
如何增加map数量?
当input文件都很大,执行逻辑复杂,map执行非常慢,可以考虑增加map数,来使得每个map处理的数量减少,提高任务执行效率。
有一个任务:
select id
, count(distinct ...)
, sum(case when ...)
, sum(case when ...)
...
from table1 group by id
;
如果table1只有一个文件块120M,但有几千万行,如果用一个map去处理这个任务,肯定会比较耗时,在这种情况下,我们可以把一个文件拆成多个文件。
set mapred.reduce.task = 10;
create table table2 as
select * from table1
distribute by rand();
这样文件table2 就通过调整reduce数量输出了10个文件块,用来代替table1。再次查询就会用10个map任务去完成。10个map任务并行去处理肯定比一个map快。