MapReduce优化
一、数据倾斜
1、大表+小表设置;
采用mapjoin把小文件放在缓存中在map端进行join操作,避免shuffle过程reduce端的join
set hive.auto.convert.join=true
2、内容倾斜
- 有数据倾斜的时候进行负载均衡(默认是false): hive.groupby.skewindata = true,生成的查询计划会有两个MR,第一个MR将key随机分发到不同的reduce达到负载均衡;第二个MR将相同的key发到对应的reduce中完成数据聚合。防止数据倾斜:
set hive.optmize.skewjoin=true;
set hive.skewjoin.key=500000;
set hive.skewjoin.mapjoin.map.tasks=10000;
set hive.skewjoin.mapjoin.min.split=335544332;
select a.*,b.* from a join b on a.userId=b.userId;
(1)join关联时有null值
select a.*,b.* from a join b on case when a.userId is null then concat("rand",rand()) else a.userId end=b.userId;
- 也可以把null单独写一个查询,写两个查询union
(2)关联时数据类型不同 - a中userId为int,b中userId字段既有string类型也int类型
- 默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中
select a.*,b.* from a join b on cast(a.userId as string)=cast(b.userId as string);
(3)map端缓慢,输入数据文件多,大小不均匀
set hive.merge.mapfiles=true;
set hive.map.aggr=true;#Combiner
- group by优化
set hive.groupby.skewindata=true;
set hive.groupby.mapaggr.checkinterval=100000;#Map端进行聚合操作的条目数
set mapred.map.task=n;#单个文件稍大于配置的block块的大小,或者map端的计算复杂/计算量大
(4)cout(distinct FIELD)如果FIELD数量特别大
select a,count(distinct b) from t group by a;
select a,sum(1) from (select a,b from t group by a,b)T group by a;
如果设置为严格模式
- 不允许扫描所有分区,查询必须加where
- rder by 必须加limit
- 限制笛卡尔积查询
- set hive.mapred.mode=strict
二、map和reduce数量设置不合理
数量都设置的太多:map、reduce任务间竞争资源,造成处理超时等错误
数量都设置的太少:会导致task等待,延长处理时间
解决方法:
设置map、reduce共存,调整slowstart.completedmaps参数,使map运行到一定程度后,reduce也开始运行,减少reduce的等待时间
三、buffer设置不合理
reduce直接从磁盘读取数据而不通过buffer
解决方法:
设置deduce端的buffer(缓存):
默认情况下,数据到达一个阀值时就会写入磁盘,可以通过配置参数使得buffer中的一部分数据可以直接输送到reduce中,减少IO开销:mapred.job.reduce.input.buffer.percent,默认为0.0。
四、任务小文件过多:
小文件会产生大量的map任务,增大map任务装载次数,而任务装载比较耗时。
输入之前对小文件进行合并
六、不可分块的超大文件
七、spill次数过多
spill次数过多,会增加磁盘的IO开销
解决方法:
通过调整io.sort.mb以及sort.spill.percent参数值,增大触发spill的内存上线,减少spill次数,从而减少磁盘IO
八、merge次数过多
merge次数过多,会增加mr处理的时间
解决方法:
通过调整io.sort.factor参数,增加merge的文件数目,减少merge的次数,从而缩短mr处理时间
九、溢出的小文件过多
map方法后,不影响业务逻辑前提下,先进行combine处理,可以减少IO