Hive中数据倾斜和小文件过多的解决方案

数据倾斜:

任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。

原因:某个reduce的数据输入量远远大于其他reduce数据的输入量

1)、key分布不均匀

2)、业务数据本身的特性

3)、建表时考虑不周

4)、某些SQL语句本身就有数据倾斜
Hive中数据倾斜和小文件过多的解决方案_第1张图片

解决方案:

(1)参数调节

set hive.map.aggr=true   
--在map端中会做部分聚集操作,效率更高但需要更多的内存,可以根据自己企业的资源情况来设置,

set hive.groupby.skewindata=true
--有数据倾斜的时候进行负载均衡 ,决定group by操作是否支持倾斜数据,其实说白了就相当于MR中的conbiner做了一次预聚合。
注意:只能对单个字段聚合。
控制生成两个MR Job,第一个MR Job Map的输出结果随机分配到reduce中减少某些key值条数过多某些key条数过小造成的数据倾斜问题。
在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个reduce 做部分聚合操作,并输出结果。这样处理的结果是,相同的 Group By Key 有可能分发到不同的reduce中,从而达到负载均衡的目的;
第二个 MapReduce 任务再根据预处理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作

(2) 可利用mapjoin进行优化(不适用所有场景)

小表在join左侧,大表在右侧,或使用mapjoin 将小表加载到内存中。然后再对比较大的表进行map操作。

join就发生在map操作的时候,这里的join并不会涉及reduce操作。map端join的优势就是在于没有shuffle,从而提升效率。

select /*+ MAPJOIN(a) */

* from a join b

where a.id = b.id;

(3) 熟悉数据的分布,优化sql的逻辑,找出数据倾斜的原因。

举例1:所有的空值都会被发送到同一个reduceTask去处理,造成数据倾斜。

        空值过滤,不参与运算或进行赋值随机数。

if(id is null,cast(rand()*-100 as bigint),id)

举例2:加盐去盐操作,使数据分散

select count(distinct id) as num from table_name


--优化1:
select count(id) as num from (select id from table_name group by id) a;
--优化2:
select sum(tag_num)  as num
from
    (select  tag
            ,count(id)  as tag_num--每个标记下的个数
    from
        (select  id
                ,CAST(RAND() * 100 AS BIGINT) tag --随机打上标记,标记为:0-100之间的整数
        from table_name 
        group by id
        ) t
    group by tag
    ) t
;
--优化3:
select sum(part_num)  as num
from
    (select  substr(id, 1, 3)              as id_part  --截取id部分做维度
            ,COUNT(DISTINCT substr(id, 4)) AS part_num --每个被截取的id下的个数
    from table_name
    group by substr(id, 1, 3)
    ) t
;

小文件过多

小文件的产生有三个地方,map输入,map输出,reduce输出,小文件过多也会影响hive的分析效率:

1、设置map输入的小文件合并

set mapred.max.split.size=256000000;  
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)  
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; 

2、设置map输出和reduce输出进行合并的相关参数:

//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000

3、通过直接对系统文件进行操作来合并小文件

你可能感兴趣的:(hive学习,hive)