hive优化策略之控制map数和reduce数


我们可以通过控制map和reduce的数量来平衡资源达到优化程序的目的。


一、map数量


map的数量与你输入的文件个数和大小有关,你可以通过set dfs.block.size;来查看集群设置的文件块大小,该参数不能自定义修改。


hive> set dfs.block.size;
dfs.block.size=134217728


例如你输入一个文件file1,大小是450M,那么hadoop会把它划分成4个块,3个128M和1个66M的文件块,从而map的数量就是4。
例如你输入四个文件file1、file2、file3、file4,大小分别是10M、20M、100M、140M,那么hadoop就会将其分成5个文件块,分别是10、20、100、128、2,从而map的数量就是5。


注意:map也不是说越多越好,如果输入的文件都是小文件,每个文件都会被当做一个文件块来进行处理,每一个文件就是一个map,因为map任务启动和初始化的时候会大于逻辑处理的时间,那么会造成资源的浪费,而且可同时执行的map数是受限制的

一个tasktracker能够同时运行最多多少个map和reduce任务
一个tasktracker能够同时运行最多多少个map任务:由mapred.tasktracker.map.tasks.maximum属性控制,默认值是2个任务。相应的,一个tasktracker能够同时运行的最多reduce任务数由mapred.tasktracker.reduce.task.maximum属性控制,默认也是2。详见《Hadoop权威指南》第二版P269页。
在一个tasktracker上能够同时运行的任务数取决于一台机器有多少个处理器。由于MapReduce作业通常是I/O-bound,因此将任务数设定为超出处理器数也有一定道理,能够获得更好的利用率。
至于到底需要运行多少个任务,则依赖于相关作业的CPU使用情况。
但经验法则是任务数(包括map和reduce任务)与处理器数的比值最好在1和2之间。


而且每个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的小文件,总大小9G,正常执行会用194个map任务。
Map总共消耗的计算资源: SLOTS_MILLIS_MAPS= 623,020


我通过以下方法来在map执行前合并小文件,减少map数:
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
再执行上面的语句,用了74个map任务,map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
对于这个简单SQL任务,执行时间上可能差不多,但节省了一半的计算资源。
大概解释一下,100000000表示100M, set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并,
前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),
进行合并,最终生成了74个块。


如何适当的增加map数?


当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
假设有这样一个任务:
Select data_desc,
count(1),
count(distinct id),
sum(case when …),
sum(case when …),
sum(…)
from a group by data_desc
如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,
这样就可以用多个map任务去完成。
set mapred.reduce.tasks=10;
create table a_1 as
select * from a
distribute by rand(123);


这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。
每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。




二、reduce数量


reduce个数的设定极大的影响任务的效率,不指定reduce个数的情况下,hive会猜测确定一个reduce个数,基于以下两个设定:
hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G)
hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)
即,如果reduce的输入(map的输出)总大小不超过1G,那么只会有一个reduce任务;
如:select pt,count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04′ group by pt;
/group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt=2012-07-04 总大小为9G多,因此这句有10个reduce


我们可以通过调整默认每个reduce处理数据的大小来进达到调整reduce的数量
调整hive.exec.reducers.bytes.per.reducer参数的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)
select pt,count(1) from popt_tbaccountcopy_mes where pt = ‘2012-07-04′ group by pt; 这次有20个reduce


也可以通过set mapred.reduce.tasks = 15;直接指定reduce的数量


同样reduce的数量也不是越多越好,因为启动reduce也会消耗时间和资源,另外有多少个reduce就会输出多少个文件,如果生成了多个小文件,那么这些小文件作为下一个任务的输入也会出现小文件过多的问题。


有3种情况下,不管你怎么设置调整reduce的个数,任务中也就一直只有一个reduce的任务。
1.没有使用group by的情况下使用select * from tablename;
2.用order by
3.使用笛卡尔积


因为这些操作都是全局的,所以hadoop不得不使用一个reduce来进行处理,同样设置reduce也需要考虑两个原则,使用大数据量利用合适的reduce数,使用单个reduce处理合适的数据量。









智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告