Hive 数据倾斜解决方案

Hive 数据倾斜解决方案:

1.调节参数
    hive.map.aggr=true  Map端部分聚合,相当于combiner
    hive.groupby.skewindata=true
        有数据倾斜的时候进行负载均衡,当选项设定为true,生成的查询计划会有两个mr job,
        第一个job中,map的输出结果集合会随机分不到reduce中,每个reduce做部分聚合操作,
        并输出结果,这样的处理结果是相同的groupByKey会分到不同的reduce中,从而达到敷在君更的目的;
        第二个job再根据预处理的数据结果按照GroupByKey分不到redcue,最终完成聚合
2. 小表和大表进行join操作
    使用map join让小的维度表(1000条以下的记录数)先进内存[distributedCache],在map端完成reduce

3.1 空值产生的数据倾斜
    赋予空值新的key值
        select *
        from log a
        left join users b
        on
        case when 
                a.user_id is null 
                then 
                concat('hive',rand())
                else a.user_id
                end = b.user_id
    好处:这个方法只有一个job,把空值的key变成了字符串加上随机数,就能把倾斜的数据分到不同的reduce上,
    解决数据倾斜问题。
3.2 不同数据类型关联产生数据倾斜
    比如 用户表user_id为int类型,log表中的user_id 字段既有int也有string类型,
    当按照user_id进行两个表的join操作时,默认的hash操作会按照int类型的id来进行分配,
    这样就会导致所有string类型的id记录都分配到一个reducer中
    解决:把数字类型转换成字符串类型
        select * 
        from 
            users a
        left outer join logs b
        on
        a.user_id = cast(b.user_id as string)
3.3 users表有600w+的记录,把users分发到所有的map也是不小的开销,而且map join不支持这么大的小表,
如果用普通的join,又会碰到数据倾斜的问题
    解决:
        select * from log a
            left outer join 
                (
                    select d.* from (select distinct user_id from log) c
                    join users d
                    on c.user_id = d.user_id
                ) x
            on a.user_id = x.user_id;

spark解决数据倾斜:

1.增加并行度,也就是增加task的个数,可以缓解数据倾斜 这样可以将分配到统一task上的key散开,
2.自定义 partition 默认是 HashPartition,这样可以将不同的key分配到多个task上,
但是也只是缓解,而且也不灵活,不能解决同一个key数据量很好的场景
3.将reduce端join变成map端join -- broadcast 
    优势:
        避免了shuffle,彻底解除了数据倾斜
    劣势:
        要求join的一侧数据集合足够小,适用于join,不适用于聚合
4.在数据倾斜的key前面加前缀,让这个key分不到不同的task中
    将有数据倾斜的RDD中倾斜Key对应的数据集单独抽取出来加上随机前缀,
    另外一个RDD每条数据分别与随机前缀结合形成新的RDD(相当于将其数据增到到原来的N    倍,N即为随机前缀的总个数),然后将二者Join并去掉前缀。然后将不包含倾斜Key的剩余数据进行Join。
    最后将两次Join的结果集通过union合并,即可得到全部Join结果。