zoukankan      html  css  js  c++  java
  • Hive-数据倾斜

    1.什么是数据倾斜

      由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点;简单来说就是key的分化严重不均,造成一部分数据很多,一部分数据很少的情况;

      比如:wordcount,最后的输出阶段形成了('aaa',1)这种格式,然后在reduce阶段进行value的增加操作,最后计算出value的总次数;若进行wordcount的文本有100G,其中80G全部时‘aaa’,剩下20G根据key不同分散到不同的reduce,进行相加的情况,如造成了数据倾斜;

      

    2.hadoop框架的特征

      (1)不怕数据大,怕数据倾斜;

      (2)jobs数比较多的作业运行效率相对比较低,如子查询比较多;

      (3)sum,count,max,min等聚合函数,通常不会有数据倾斜问题;

    3.主要表现

      任务进度长时间维持在99%或者100%的附近,查看任务监控页面,发现只要少量reduce子任务完成,因为其处理的数据量和其他的reduce差异过大;单一reduce处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大于平均时长;

      

    4.易产生数据倾斜的情况

      

      (1)group by不和聚集函数搭配使用的时候l;

      (2)count(distinct)在数据量大的情况下,容易数据倾斜,因为count(distinct)是按group by字段分组,按distinct字段排序;

      (3)小表关联超大表join;

    5.业务场景

      5.1 空值产生的数据倾斜

        场景:在日志中,常常会有信息丢失问题,比如日志中user_id,如果取其中user_id和用户表中的user_id相关联,就会碰到数据倾斜的问题;

        解决方案:

          方式一:user_id为空的不参与关联

    #以下HQL字句为伪案例,意在表明案例
    select * from log a join user b on a.user_id is not null and a.user_id = b.user_id
    union all
    select * from log c where c.user_id is null;

          方式二:赋予user_id为空的列新值

    select * from log a left outer join user b on
    case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id

          方式一和方式二直接的对比:

            方式二比方式一效率更好,不但IO少了,而且作业书也少了,方式一种log表读了两次,jobs肯定2,而方式二是1,这个优化适合无效id产生的数据倾斜,把控制的key变成一个字符串加上一个随机数,就能把造成数据倾斜的数据分到不同的reduce上解决数据倾斜的问题;

            改变之处,是本身为null的所有记录不会拥挤在同一个reduceTask了,会由于有替代的随机字符串值,而分散了多个reduceTask中了,由于null值关联不上,处理后并不影响最终结果;

      5.2 不同数据类型关联产生的数据倾斜

        场景:用户表中user_id字段为int,log表中user_id为既有string也有int类型,当按照两个表的user_id进行join操作的时候,默认的hash操作会按照int类型的id进行分配,这样就会导致所有的string类型的id就被分到同一个reducer当中;

        解决方案:

    select * from user a left outer join log b on b.user_id = cast(a.user_id as string);

      5.3 大小表关联

        注意:使用map join解决小表关联大表造成的数据倾斜问题;这个方法使用的频率很高;

        map join概念:将其中做连接的小表(全量数据)分发到所有mapTask端进行join,从而避免了reduceTask,前提要求是内存足以装下该全量数据;

          

         以大表a和小表b为例,所有的mapTask节点都装载小表b的所有数据,然后大表a的一个数据块数据比如说是a1去跟b全量数据做连接,就省去了reduce做汇总的过程;所有相对来说,在内存允许的条件下使用mapjoin比直接使用MapReduce效率还高些,当然这只限于join查询的时候;

        在hive,直接提供了能够在HQL语句指定该次查询使用map join,map join的用法是在查询/子查询的select关键字后面添加/*+MAPJOIN(tablelist)*/提示优化器转化为mapjoin;气筒tablelist可以是一个表,或是以逗号连接的表的列表;tablelist中的表将会读入内存,通常应该是将小表写在这里;

        mapjoin具体用法:

    select /* +mapjoin(a) */ a.id aid, name, age from a join b on a.id = b.id;

        在hive0.11版本以后会自动开启map join优化,由以下两个参数控制:

    set hive.auto.convert.join=true; #设置 MapJoin 优化自动开启
    set hive.mapjoin.smalltable.filesize=25000000 #设置小表不超过多大时开启 mapjoin 优化

        如果是大表关联大表呢?

          那就将大表分割成为小表,然后使用map join;

        使用map join解决小表(记录数少)关联大表的数据倾斜问题,这个方法使用的频率非常高,但如果小表很大,大到map join会出现bug或异常,这时就需要特别的处理;

        举例:日志表和用户表做关联

    select * from log a left outer join users b on a.user_id = b.user_id;

          user表有600w+的记录,把users分发到所有的map上也是个不小的开销,而且map join不支持这么大的下表;如果用普通的join,又会碰到数据倾斜的问题;

          改进方案:

    select /*+mapjoin(x)*/* from log a #大表--->小表
    left outer join (
     select /*+mapjoin(c)*/ 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;
  • 相关阅读:
    linux内核中GNU C和标准C的区别
    linux内核中GNU C和标准C的区别
    Getting start with dbus in systemd (02)
    Getting start with dbus in systemd (01)
    Getting start with dbus in systemd (03)
    物理内存相关的三个数据结构
    数据类型对应字节数(32位,64位 int 占字节数)
    Linux kernel 内存
    共模电感的原理以及使用情况
    [原创]DC-DC输出端加电压会烧毁
  • 原文地址:https://www.cnblogs.com/wnwn/p/12773011.html
Copyright © 2011-2022 走看看