一、任务数
1.1、map任务数
1.2、reduce任务数
二、文件合并
2.1、输入合并
2.2、输出合并
三、map端聚合
四、map join
五、总结
一、任务数
1.1、map任务数
hadoop会根据某种策略将输入数据切分成多个split,一个split需要一个map task处理;split只是逻辑上对数据分片,并不会物理上将数据切分成多个split,实际上HDFS上数据还是以block为基本单元存储。一个小文件(文件大小<块大小)需要一个map 处理。
splitSize=max{minSize,min{goalSize,blockSize}}
minSize=mapred.min.split.size 每个map task处理的最小数据大小
numSplits=mapred.map.tasks 期望的map数
totalSize=输入文件总体大小
goalSize=totalSize/numSplits 期望的分片大小
blockSize=dfs.block.size 块大小
map task数=totalSize/splitSize
1、如果想减少map个数,即增大splitSize,则设置mapred.min.split.size为一个较大值
2、如果想增加map个数,即减小splitSize,则设置mapred.map.tasks为一个较大值
一个map处理的split分片(处理的数据量<=splitSize)可能是分布在多个节点上的块(一个map处理多个块),这就会使得map task在执行过程中涉及到读取其他节点上的block数据,从而不能实现数据本地性,造成更多网络开销。应尽量保证分片大小和块大小相同。
1.2、reduce任务数
mapred.reduce.tasks/mapreduce.job.reduces:job默认的reduce task数,默认值是-1;如果值是负数,hive会自动计算需要的reduce task数
hive.exec.reducers.max:设置job可以启动的最大reduce task数,0.14以前版本默认是999,以后版本默认是1009;
1、mapred.reduce.tasks<=-1
reduce task数量=min(hive.exec.reducers.max ,总输入数据量/ hive.exec.reducers.bytes.per.reducer)
2、mapred.reduce.tasks >1
reduce task数量=min(hive.exec.reducers.max,mapred.reduce.tasks)
一个reduce会有一个输出文件,如果reduce任务数比较多
二、文件合并
2.1、输入合并
如果一个map任务的输入有很多小文件(远远小于块大小),那么每个小文件都会用一个map任务来处理,而每个map函数的启动和初始化时间会远远大于业务逻辑处理时间,造成资源极度浪费,而且可执行的map数也是受限的,这时需要对文件进行输入合并。
hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
mapred.max.split.size=100000000;
mapred.min.split.size.per.node=100000000;
mapred.min.split.size.per.rack=100000000;
2.2、输出合并
Hadoop中大量的小文件,会给HDFS带来压力,hive的查询效率也有低很多。hive在job执行完后,可以控制是否需要合并小文件, 如果满足一定的要求,会单独启一个job来合并文件。
hive.merge.smallfiles.avgsize=16000000 设置合并小文件的标准:当输出的文件平均大小小于设置的阀值时,hive会单独启动一个mapreduce把输出的文件合并成大文件
hive.merge.size.per.task=256000000合并后的每个文件目标大小
hive.merge.mapfiles=truemap only任务结束后,是否合并map输出的文件
hive.merge.mapredfiles=truereduce任务结束后,是否合并reduce输出的文件
三、Map端聚合
并不是所有的聚合操作都需要在reduce端完成,很多聚合操作都可以先在 map 端进行局部聚合,最后在reduce端聚合后,再输出最终结果,这样可以减少传输的数据量,提高执行效率
hive.map.aggr:Goup By查询中是否用map端聚合
hive.map.aggr.hash.force.flush.memory.threshold: map端聚合使用的最大内存,默认是0.9;如果使用的内存高于设定的阀值,会强制刷新数据
hive.map.aggr.hash.percentmemory:map端聚合使用的最大内存占用百分比,默认值0.5
四、map-join
适用于小表JOIN大表的场景,由于表的JOIN操作是在Map端且在内存进行的,所以其并不需要启动Reduce任务也就不需要经过shuffle阶段,从而能在一定程度上节省资源提高JOIN效率。
hive.auto.convert.join :如果设为true,hive会根据输入文件的大小,判断是否把普通join转为mapjoin
hive.mapjoin.smalltable.filesize:小表输入的阀值,默认是250M(25000000),如果文件大小小于设定的阀值,会把普通join转换成map join
多表查询也可以使用map join,如果预先知道表大小是能够转载进内存的,则可以通过下面的配置项控制:
hive.auto.convert.join.noconditionaltask:基于文件大小是否将普通join转换为map join,且多个map join是否合并成成一个map join
hive.auto.convert.join.noconditionaltask.size:输入文件的总大小,默认值是10M(10000000)
五、总结
hive的优化不是一撮而就的,需要持续不断的跟踪,具体问题具体分析,本文也只是提供了一种优化思路,供大家参考。
其他的常用优化方式还有对表进行分桶、文件压缩、使用内存表等,这些再以后再介绍。
加入KETTLE技术交流群,分享学习心得,一起共同进步。
QQ群:452881901,扫下方二维码快速加群:
点击下方阅读《JStorm基本概念介绍》