主要对基于MR的map数和reduce数测试与调优
本次测试的表和sql都是使用的TPC-DS,表文件存储格式为text
表名 |
是否压缩 |
总数 |
占用空间 |
文件数 |
date_dim |
否 |
73049 |
9.8 M |
1 |
item |
否 |
48000 |
12.9 M |
1 |
store |
否 |
118 |
30.5 K |
1 |
store_sales |
否 |
23039641872 |
3109G |
8000 |
store_sales_compress |
是 |
23039641872 |
825.3 G |
3515 |
store_sales事实大表的数据块分布
单个文件占用空间 |
380-400M |
400M以上 |
文件数 |
7927 |
73 |
store_sales的表结构:
# 查看表的结构
show create table store_sales;
测试SQL为CPU密集型,密集型的含义:在SQL运行期间CPU占比会很高
Hive中来控制map数量的参数不是Hive本身的参数,而是MapReduce的参数,但是可以通过在Hive中使用set的形式来使用。影响map个数的hive参数如下表:
参数 |
默认值 |
说明 |
mapreduce.input.fileinputformat.split.maxsize |
256000000 |
每个Map的最大输入 |
mapreduce.input.fileinputformat.split.minsize |
1 |
每个Map的最小输入 |
mapred.map.task |
2 |
Task数量 |
hive.input.format |
org.apache.hadoop.hive.ql.io. CombineHiveInputFormat |
输出格式 |
dfs.block.size |
134217728 |
默认的block块大小 |
说明:dfs.block.size参数不能通过Hive的set语句来设置,只能通过修改HDFS的参数来设置。
当输入类型为HiveInputFormat时,map数量由以下参数控制,且剩余的小文件不会合并:
参数 |
默认值 |
说明 |
mapreduce.input.fileinputformat.split.minsize |
1 |
每个Map的最小输入 |
mapred.map.task |
2 |
Task数量 |
dfs.block.size |
134217728 |
默认的block块大小 |
文件的分割大小满足下面的公式:
splitSize= max{ mapreduce.input.fileinputformat.split.minsize ,min{ dfs.block.size , 表大小 / mapred.map.task } }
测试1:
参数设置:
mapred.map.tasks=2;
mapreduce.input.fileinputformat.split.minsize=1;
结果打印:
Hadoop job information for Stage-4: number of mappers : 29930 ; number of reducers :1009
共有29930个map数
根据公式可以计算出来,文件分割大小为dfs.block.size的值,128M。
store_sales表总共有8000个文件,数据量分布在380-410M之间。
例子:
一个400M的文件,理论上根据128M分割,会分割成4个文件。(128M,128M,128M,16M)
一个350M的文件,理论上根据128M分割,会分割成3个文件。(128M,128M,94M)
所以map数应该在3*8000 ~ 4*8000之间。结果值29930满足上述公式。
测试2:
参数设置:
mapred.map.tasks=2;
mapreduce.input.fileinputformat.split.minsize=256000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 16000 ; number of reducers :1009
共有16000个map数
根据公式可以计算出来,文件分割大小为mapreduce.input.fileinputformat.split.minsize的值为244M。
每个文件都被分成两个文件,所以map数为16000。
测试3:
参数设置:
mapred.map.tasks=2;
mapreduce.input.fileinputformat.split.minsize= 512000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 8000; number of reducers :1009
总共有8000个map数
根据公式可以计算出来,文件分割大小为mapreduce.input.fileinputformat.split.minsize的值为488M。
每个文件都被分成一个文件,所以map数为8000。
测试4:
参数设置:
mapred.map.tasks=2;
mapreduce.input.fileinputformat.split.minsize= 1024000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 8000 ; number of reducers :1009
总共有8000个map数
根据公式可以计算出来,文件分割大小为mapreduce.input.fileinputformat.split.minsize的值为488M。
每个文件都被分成一个文件,所以map数为8000。
当输入类型为CombineHiveInputFormat时,map数量由以下参数控制,剩余的小文件会合并:
参数 |
默认值 |
说明 |
mapreduce.input.fileinputformat.split.maxsize |
256000000 |
每个Map的最大输入 |
测试1:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=256000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 12001; number of reducers :1009
总共有12001个map数
由于CombineHiveInputFormat,会对小文件进行合并,所以需要根据数据的总量去计算map数,3000 * 1024 / 12000≈256000000
测试2:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=128000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 24001; number of reducers :1009
总共有24001个map数
测试3:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=512000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 6001; number of reducers :1009
总共有6001个map数
测试4:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=1024000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 3001; number of reducers :1009
总共有3001个map数
压缩相关参数
参数 |
默认值 |
说明 |
io.compression.codecs |
org.apache.hadoop.io.compress.GzipCodec, org.apache.hadoop.io.compress.DefaultCodec, org.apache.hadoop.io.compress.SnappyCodec |
Hive配置可用的压缩算法 |
hive.exec.compress.output |
false |
开启压缩 |
mapreduce.output.fileoutputformat.compress.codec |
org.apache.hadoop.io.compress.DefaultCodec |
使用的压缩算法 |
测试使用store_sales_compress表,Text格式,压缩格式为DefaultCodec,文件都是.deflate结尾的。DefaultCodec不支持文件切分,每个文件大小分布在280M~340M之间
表名 |
是否压缩 |
总数 |
占用空间 |
文件数 |
store_sales_compress |
是 |
23039641872 |
825.3 G |
3515 |
测试1:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=512000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 3515; number of reducers :1009
总共有3515个map数
测试2:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=256000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 3515; number of reducers :1009
总共有3515个map数
因为文件存储使用了DefaultCodec压缩,且DefaultCodec压缩不支持文件切分,所以我们设置参数为256000000时没有生效。
测试3:
参数设置:
mapreduce.input.fileinputformat.split.maxsize=128000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 3515; number of reducers :1009
总共有3515个map数
因为文件存储使用了DefaultCodec压缩,且DefaultCodec压缩不支持文件切分,所以我们设置参数为128000000时没有生效。
mapreduce.input.fileinputformat.split.minsize值 |
Map数 |
1 |
29930 |
256000000 |
16000 |
512000000 |
8000 |
1024000000 |
8000 |
3.2.2 CombineHiveInputFormat
mapreduce.input.fileinputformat.split. maxsize值 |
Map数 |
256000000 |
12001 |
128000000 |
24001 |
512000000 |
6001 |
1024000000 |
3001 |
mapreduce.input.fileinputformat.split. maxsiz值 |
Map数 |
512000000 |
3515 |
256000000 |
3515 |
128000000 |
3515 |
参数 |
默认值 |
说明 |
mapred.reduce.tasks |
-1 |
指定reduce的个数 |
hive.exec.reducers.bytes.per.reducer |
67108864 |
每个reduce的数据处理量 |
hive.exec.reducers.max |
1009 |
reduce的最大个数 |
reduce的个数满足下面的公式:
reduce=min(hive.exec.reducers.max, map input数据大小/hive.exec.reducers.bytes.per.reducer)
reduce的个数控制相对于map就要简单很多,并且可以精确地来控制reduce的个数。
(1)mapred.reduce.tasks
可以通过修改mapred.reduce.tasks的值来精确控制reduce的个数。默认情况下不设置,除非对于某个特定的SQL语句可以单独设置,但是功能上没有hive.exec.reducers.max来的方便。
其中,每个reduce处理的数据为(总数据量 /设置的reduce个数)。
测试1:
参数设置:
set mapred.reduce.tasks=200;
结果打印:
Hadoop job information for Stage-4: number of mappers : 12001; number of reducers :200
总共有200个reduce,从上述的1009个变成200个。
(2)hive.exec.reducers.bytes.per.reducer
测试1:
参数设置:
set hive.exec.reducers.bytes.per.reducer = 67108864;
结果打印:
Hadoop job information for Stage-4: number of mappers : 12001; number of reducers :1009
共有1009个reduce数
根据公式可以计算出:
3109 * 1024 / (67108864/ 1024 /1024 ) = 49744 > 1009,所以reduce个数为1009
测试2:
参数设置:
set hive.exec.reducers.bytes.per.reducer = 4096000000;
结果打印:
Hadoop job information for Stage-4: number of mappers : 12001; number of reducers :816
共有816个reduce数
根据公式可以计算出:
3109 * 1024 / (4096000000 / 1024 /1024 ) = 815 < 1009 ,根据结果需要取815值。算出来的值也基本等于上面的816
(1)map
基于MR,先判断文件是否压缩,且压缩文件是否支持切分,再判断是hive.input.format的实现类。然后使用相对应的参数进行map数调优。
(2)reduce
需要根据集群的资源以及map端实际的输出数据量来设置reduce数。
(1)map
当使用压缩时,如果压缩文件不可切分,那么久不能通过修改参数来改动map数。所以在选择压缩算法时,需要考虑该压缩算法是否支持文件切分。
在MR作为引擎的情况下,推荐使用CombineHiveInputFormat,而不是HiveInputFormat
需要通过测试来得到性能好的map数。不是越多越好,也不是越少越好
(2)reduce
推荐reduce数为集群能启动的最大container数的80%,或者小于这个数。
mapred.reduce.tasks这个参数一般不推荐使用。