首页 > 代码库 > Hive参数层面优化之一控制Map数
Hive参数层面优化之一控制Map数
1、Map个数的决定因素
通常情况下,作业会通过input文件产生一个或者多个map数;
Map数主要的决定因素有: input总的文件个数,input文件的大小和集群中设置的block的大小(在hive中可以通过set dfs.block.size命令查看,该参数不能自定义修改);
文件块数拆分原则:如果文件大于块大小(128M),那么拆分;如果小于,则把该文件当成一个块。
举例一:
假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块,Block是128M),从而产生7个map数;
实例二:
假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数;
两种方式控制Map数:即减少map数和增加map数
减少map数可以通过合并小文件来实现,针对文件源;
增加map数的可以通过控制上一个job的reduer数来控制(一个sql中join多个表会分解为多个mapreduce),因为上一个job的reduce输出数决定了这个job的map数;
2、Map数过大或过小引发的问题
Map数过大将导致:
1) Map阶段输出文件太小,产生大量小文件;当下一个阶段被使用时,需要合并小文件;多个小文件如果被reduce处理的话,就需要有很多个reduce数;
2) 初始化和创建Map的开销很大;
3) 如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时一个JOB可执行的map数也是受限的
Map数太小将导致:
1) 文件处理或查询并发度小,Job执行时间过长;
2) 大量作业时,容易堵塞集群;
3) 频繁推测执行;
是不是保证每个map处理接近128M的文件块,就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
3、设定map数:mapred.map.tasks
当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率;
hive中map数默认值是2;
案例环境描述:
hive.merge.mapredfiles=true (默认是false,可以在hive-site.xml里配置,在整个job执行后合并)
hive.merge.mapfiles=true map执行后合并
hive.merge.size.per.task=256000000
mapred.map.tasks=2 hive中map数默认是2
因为合并小文件默认是true,而dfs.block.size与hive.merge.size.per.task的搭配使得合并后的绝大部分文件都在256M左右;
案例一:
现在我们假设有3个300MB大小的文件,每个BLOCK大小为256M而且不设定map数;
整个JOB会有6个map,其中3个map分别处理256MB的数据,还有3个map分别处理44MB的数据;
木桶效应就来了,整个JOB的map阶段的执行时间不是看最短的1个map的执行时间,而是看最长的1个map的执行时间。所以,虽然有3个map分别只处理44MB的数据,可以很快跑完,但它们还是要等待另外3个处理256MB的map。显然,处理256MB的3个map拖了整个JOB的后腿。
案例二:
如果我们把mapred.map.tasks设置成6,再来看一下有什么变化:
goalsize = min(900MB/6,256MB) = 150MB
整个JOB同样会分配6个map来处理,每个map处理150MB的数据,非常均匀,谁都不会拖后腿,最合理地分配了资源,执行时间大约为CASE 1的59%(150/256)
案例三:
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(几百万记录)的数据,效率肯定会好很多。
4、Map数总结
看上去,貌似这两种有些矛盾,一个是要合并小文件,一个是要把大文件拆成小文件,这点正是重点需要关注的地方, 根据实际情况,控制map数量需要遵循两个原则:
1) 使大数据量利用合适的map数;
2) 使单个map任务处理合适的数据量;