1合理设置Map数
1)通常情况下,作业会通过input的目录产生一个或者多个map任务。
主要的决定因素有:input的文件总个数,input的文件大小,集群设置的文件块大小。
举例:
a)假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个map数。
b)假设input目录下有3个文件a,b,c大小分别为10m,20m,150m,那么hadoop会分隔4个块(10m,20m,128m,22m),从而产生4个map数。即,如果文件大于块于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
2)是不是map数越多越好?
答案是否定的。如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数受限的。
3)是不是保证每个map处理接近128m的文件块就高枕无忧了?
答案也是不一定。比如有一个127m的文件,正常会用一个map去完成,但这个文件只有一个或者两个小字段,却有几千万的记录,如果map处理的逻辑比较复杂,用一个map任务去做,肯定也比较耗时。
针对上面的问题2和3,我们需要采取两种方式来解决:即减少map数和增加map数;
2小文件合并
在map执行前合并小文件,减少map数:
CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)
set mapred.max.split.size=112345600;
set mapred.min.split.size.per.node=112345600;
set mapred.min.split.size.per.rack=112345600;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。
3 复杂文件增加map数
当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
增加map的方法为
根据
computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize))公式
调整maxSize最大值。让maxSize最大值低于blocksize就可以增加map的个数。
mapreduce.input.fileinputformat.split.minsize=1 默认值是1
mapreduce.input.fileinputformat.split.maxsize=Long.MAXValue
默认值Long.MAXValue因此,默认情况下,切片大小=blocksize
maxsize(切片最大值):参数如果调到比blocksize小,则会让切片变小,而且就等于配置的这个参数的值。
minsize(切片最小值):参数调的比blockSize大,则可以让切片变得比blocksize还大。
例如:
--设置maxsize大小为10m,也就是说一个fileSplit的大小为10m
set mapreduce.input.fileinputformat.split.maxsize=10485760;
4合理设置Reduce数
1、调整reduce个数方法一
1)每个Reduce处理的数量默认是256MB
set hive.exec.reducers.bytes.per.reducer=2560000000;
2)每个任务最大的reduce数,默认为1009
set hive.exec.reducers.max=1009;
3)计算reducer数的公式
N=min(参数2,总输入数据量/参数 1)
2、调整reduce个数方法二
--设置每一个job中reduce个数
set mapreduce.job.reduces=3;
3、reduce个数并不是越多越好
过多的启动和初始化reduce也会消耗时间和资源;
同时过多的reduce会生成很多个文件,也有可能出现小文件问题。