1.概述
主要对基于MR的map数和reduce数测试与调优
2.数据准备
(1)表信息
本次测试的表和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;
(2)SQL 语句
测试SQL为CPU密集型,密集型的含义:在SQL运行期间CPU占比会很高
3.map数的控制
3.1 map数控制测试
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的参数来设置。
3.1.1 HiveInputFormat
当输入类型为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。
3.1.2 CombineHiveInputFormat
当输入类型为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数
3.1.3 Text格式文件压缩
压缩相关参数
参数 | 默认值 | 说明 |
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时没有生效。
3.2 map数控制结果
3.2.1 HiveInputFormat
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 |
3.2.3 Text格式文件压缩
mapreduce.input.fileinputformat.split. maxsiz值 | Map数 |
512000000 | 3515 |
256000000 | 3515 |
128000000 | 3515 |
4.reduce数的控制
4.1 影响reduce个数的参数
参数 | 默认值 | 说明 |
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
5.调优流程
(1)map
基于MR,先判断文件是否压缩,且压缩文件是否支持切分,再判断是hive.input.format的实现类。然后使用相对应的参数进行map数调优。
(2)reduce
需要根据集群的资源以及map端实际的输出数据量来设置reduce数。
6.总结
(1)map
-
当使用压缩时,如果压缩文件不可切分,那么久不能通过修改参数来改动map数。所以在选择压缩算法时,需要考虑该压缩算法是否支持文件切分。
-
在MR作为引擎的情况下,推荐使用CombineHiveInputFormat,而不是HiveInputFormat
-
需要通过测试来得到性能好的map数。不是越多越好,也不是越少越好
(2)reduce
-
推荐reduce数为集群能启动的最大container数的80%,或者小于这个数。
-
mapred.reduce.tasks这个参数一般不推荐使用。