1. Map数的计算公式为:
num_Map_tasks=
max[${Mapred.min.spilt.size},min(${dfs.block.size},${Mapred.max.split.size})]
Mapred.min.spilt.size指的是数据的最小分割单元大小(默认为1B)
Mapred.max.split.size指的是数据的最大分割单元大小(默认为256MB)
dfs.block.size指的是HDFS设置的数据块大小(这个值是在配置文件中定好的,而且Hive是获取不到的)
所以Map的数量是由Mapred.min.spilt.size、Mapred.max.split.size这两个参数的最大值决定的。如果不做修改的话一个Map Task处理256MB的数据,增大Mapred.max.split.size的值可以减少Map的数量,减少Mapred.max.split.size的值可以增大Map的数量。但是直接修改Mapred.Map.tasks是没有效果的。如果运行速度较慢,可以考虑增加Map的数量,增加并行度,如果运行速度较快,增加Map数量不太可能加快速度,反而有可能因为初始化Map使速度变慢,此时可以考虑减少Map,这样可以节省更多资源给其他Job
二、Reduce阶段的优化(Reudcephase)
1. Map数的计算公式为:
num_Reduce_tasks=
min[${Hive.exec.Reduces.max},(${input.size}/ ${Hive.exec.Reducers.bytes.per.Reducer})]
Hive.exec.Reducers.bytes.per.Reducer(默认值为1G)
所以Reduce的数量是由输入的数据量大小决定的,但是Reduce的数量不能超过999,可以通过设置Hive.exec.Reducers.bytes.per.Reducer来设置Reduce的个数,也可以通过设置Mapred.Reduce.tasks来设置Reduce的数量。
三、Map与Reduce之间的优化(Spill、Copy、Sort phase)
1. 在Spill阶段,由于内存不够,数据需要溢写到磁盘再排序,然后对所有的文件进行Merge。可以通过设置io.Sort.mb来增大环形缓冲区的大小,避免Spill
一、文件格式的优化(TextFile、SequenceFile、RCFile)
1. Hive的默认配置可以将对个小文件合并成一个Map处理,输出时如果文件很小也会自动合并,所以不用设置了。关于文件格式,上述三种RCFile的压缩比例和查询时间都比较好一些,可以在创建表时设置指定。
例如:create tablerc_file_test(id int)stored asrcfile;
然后设置参数set Hive.exec.compress.output=true;指定输出格式
另外可以设置Hive.default.fileformat来设定输出格式,适用于createtable as select
例如:set Hive.default.fileformat=SequenceFile; setHive.exec.compress.output=true;
SequenceFile有record和block两种压缩方式,block压缩比更高
SetMapred.output.compression.type=BLOCK; create table seq_file_test as select *from a;
二、Job执行模式的优化
1. Hadoop的Job分为三种模式,分别为本地模式、伪分布式、完全分布式。
set Hive.exec.mode.local.auto=true,此时默认情况下如果处理的文件不超过4个,并且总大小不超过128MB就会启用local模式
三、JVM重用
1. 正常情况下MapReduce启动JVM完成一个task后就退出了,如果任务花费时间短,但又要多次启动JVM的情况下(比如对很大数据量进行计数操作),JVM的启动的启动时间就会变成一个比较大的overhead(开销),这种情况下可以通过设置
Mapred.Job.reuse.jvm.num.tasks=5; 可以让JVM运行多次任务之后再退出
四、**数据倾斜**
1. 比如有个场景:未注册用户user_id=0,注册用户有唯一的user_id,那么对于user_id的group by和join时,某个Reduce会收到比其他Reduce更多的数据。
如果是group by造成的,有两个参数可以解决:第一个是Hive.Map.aggr,他的默认值为true,意思是会做Map端的Combiner,所以count(*)是看不出区别的,但是
count(distinct)会有一些倾斜。另一个参数是Hive.groupby.skewindata,这个参数的意思是在Reduce操作时,拿到的Key不是相同值分给同一个Reduce,而是随机分发(在每个可以后面拼接随机字符串),然后Reduce做聚合,做完之后再进行一轮MR,因为要额外启动一次Job,效果不明显,不推荐使用。
如果是join造成的,可以使用skew join,其原理是把特殊值先不在Reduce端计算掉,而是先写入HDFS,然后启动一轮Map join专门做这个特殊值的计算。需要设置
set Hive.optimize.skewjoin=true; 然后根据Hive.skewjoin.key的值来判断超过多少条算特殊值。这种情况可以在SQL语句里将特殊值隔离开来避免数据倾斜:
改写前:select a.* from logs a join users b on a.user_id = b.user_id;
改写后:
select a.* from (
select a.*
from (select * from logs where user_id = 0) a
join (select * from users where user_id = 0) b
on a。user_id = b。user_id
union all
select a.*
from logs a join users b
on a.user_id <> 0 and a。user_id = b.user_id )t;
五、Join算法
1. 处理分布式join,一般有两种方法:
replication join:把其中一个表复制到所有节点,这样另一个表在每个节点上面的分片就可以跟这个完整的表join了;
repartition join:把两份数据按照join key进行hash重分布,让每个节点处理hash值相同的join key数据,也就是做局部的join。
在MR中,replication join对应Map side join;repartitionjoin对应Reduce side join;
Hive默认使用的是Reduce side join,但是在其中一张表较小时,可以考虑使用Mapside join,因为小表的复制代价小于大表shuffle的代价。Set Hive.auto.convert.join=true;
Hive会根据Hive.smalltable.filesize的参数来判断是否该使用Map sidejoin,默认小于25MB算小表。