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;
  • 相关阅读:
    android studio 各种问题
    关于Android开发中Arm、X86和Mips(草稿)
    每日更新
    Error creating bean with name 'userRepository': Invocation of init method failed;
    API 'variant.getJavaCompiler()' is obsolete and has been replaced with 'variant.getJavaCompileProvider()'
    increase the minSdkVersion to 26
    Exception thrown on Scheduler.Worker thread. Add `onError` handling
    M600 Pro 安装问题解决
    Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed.
    大疆无人机M100相关问题解决过程
  • 原文地址:https://www.cnblogs.com/wnwn/p/12773011.html
Copyright © 2011-2022 走看看