大数据之Hive Mapper和Reducer数量设置

目的:

深入认识hive 以mapreduce 为计算引擎时Mapper 和Reducer的设置

背景;

运营团队反映,公司广告业务的日活用户数据量偶尔呈剧烈下降趋势,同时出现用户数低于日活用户数据的问题,后来查看离线解析任务,执行过程正常但是数据的加载却除了问题——部分文件并没有加载到操作型数据库(提供数据展示的库,infobright)

大数据之Hive Mapper和Reducer数量设置_第1张图片

 

问题分析:

由于load 数据时只加载了000000_0 文件,所以导致数据库中数据不齐全,同时产生的结果文件数量和Reducer 的个数相关。


认识InputFormat 接口

简单说就是用于描述数据的输入格式,

@Public
@Stable
public interface InputFormat {
 InputSplit[] getSplits(JobConf var1, int var2) throws IOException;
 RecordReader getRecordReader(InputSplit var1, JobConf var2, Reporter var3) throws IOException;
}
从源码可以看出,该接口下的两个方法的功能分别是将输入的文件分片(splits)和将输入的splits 转化成key-value 数据,
hive> set hive.input.format;
hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
也可通过hive-site.xml 配置文件可确认使用的那种InputFormat,也可以设置为其他的输入格式
 
 hive.input.format
 org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
 The default input format. Set this to HiveInputFormat if you encounter problems with CombineHiveInputFormat.
 
默认使用的是CombineHiveInputFormat,其作用是将多个小文件组合成一个split 使用一个Mapper 处理,避免因太多的小文件生成大量任务,耗用资源。

Mapper 个数的计算

 如果 hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat,采用文件分割算法。
 文件切分算法主要用于确定InputSplit的个数以及每个InputSplit对应的数据段,FileInputSplit以文件为单位切分生成InputSplit。有三个属性值来确定InputSplit的个数:
 goalSize:该值由 totalSize/numSplits 来确定 InputSplit 的长度,它是根据用户的期望的 InputSplit 个数计算出来的;numSplits 为用户设定的 Map Task 的个数,默认为1。
 minSize:由配置参数 mapred.min.split.size(或者 mapreduce.input.fileinputformat.split.minsize)决定的 InputForma t的最小长度,默认为1。
 blockSize:HDFS 中的文件存储块block的大小,不同版本的hadoop的默认不一样,2.0 之前的hadoop 的blocksize 默认是64MB,2.0 后的默认值是128M。
 numSplits=mapred.map.tasks 或者 mapreduce.job.maps
 
 最终:
 InputFormat 分片的长度:splitSize = max{minSize,min{goalSize,blockSize}} 
 
 如果hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,采用host 选择算法。
 long left = locations[i].getLength();
 long myOffset = locations[i].getOffset();
 long myLength = 0;
 do {
 	if (maxSize == 0) {
 		myLength = left;
 	} else {
 	if (left > maxSize && left < 2 * maxSize) {
 	 myLength = left / 2;
 	} else {
 	 myLength = Math.min(maxSize, left);
 	}
 	}
 	OneBlockInfo oneblock = new OneBlockInfo(path, myOffset,
 	 myLength, locations[i].getHosts(), locations[i]
 	 .getTopologyPaths());
 	left -= myLength;
 	myOffset += myLength;
 	blocksList.add(oneblock);
 } while (left > 0);
 根据以下几个参数确定splitsize
 hive> set mapred.min.split.size;
 mapred.min.split.size=1
 hive> set mapred.max.split.size;
 mapred.max.split.size=67108864
 hive> set mapred.min.split.size.per.rack;
 mapred.min.split.size.per.rack=1
 hive> set mapred.min.split.size.per.node;
 mapred.min.split.size.per.node=1
 hive> set dfs.blocksize;
 dfs.blocksize=134217728

参考别人的测试用例:

如果 hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat,则这时候的参数如下:

hive> set mapred.min.split.size;
mapred.min.split.size=1
hive> set mapred.map.tasks;
mapred.map.tasks=2
hive> set dfs.blocksize;
dfs.blocksize=134217728

上面参数中 mapred.map.tasks 为2,dfs.blocksize(使用的是 cdh-4.3.0 版本的 hadoop,这里 block 和 size 之间没有逗号)为128M。

假设有一个文件为200M,则按上面 HiveInputFormat 的 split 算法:

1、文件总大小为200M,goalSize=200M /2 =100M,minSize=1 ,splitSize = max{1,min{100M,128M}} =100M

2、200M / 100M >1.1,故第一块大小为100M

3、剩下文件大小为100M,小于128M,故第二块大小为100M。

如果 hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,则这时候的参数如下:

hive> set mapred.min.split.size;
mapred.min.split.size=1
hive> set mapred.max.split.size;
mapred.max.split.size=67108864
hive> set mapred.min.split.size.per.rack;
mapred.min.split.size.per.rack=1
hive> set mapred.min.split.size.per.node;
mapred.min.split.size.per.node=1
hive> set dfs.blocksize;
dfs.blocksize=134217728

上面参数中 mapred.max.split.size 为64M,dfs.blocksize 为128M。

假设有一个文件为200M,则按上面 CombineHiveInputFormat 的 split 算法:

1、128M < 200M <128M X 2,故第一个block大小为128M

2、剩下文件大小为200M-128M=72M,72M < 128M,故第二块大小为72M


Reducer 个数计算

设置为指定大小 set mapred.reduce.tasks=10

如果reducer 数量没有指定,默认为-1,执行任务是hive 则会计算reducer 的数量

hive.exec.reducers.bytes.per.reducer 每个reducer 的默认大小默认1GB。(hive 1.2 默认是256 M)

hive.exec.reducers.max 每个任务最大的reduce数,默认为999 (hive 1.2 默认是1009)

reducerNum=min(参数2,输入文件大小/参数1)

总结:

关于hive 执行sql 到处数据文件时,文件的个数与hive 执行到最后stage的reducer 的数量相关。reducer 的数量如果设置过大,怎会生成的小文件就会更多,如果reducer 的数量设置的太少,可能导致所有的一个reducer 处理更多的文件,易引起OOM。

因理解不到位,在此分享使用过程遇到的问题,共勉。

你可能感兴趣的:(互联网,大数据,人工智能)