Hive中存在的数据倾斜问题

真是好久没写博客了。。。趁着今天休息,把以前遇到的问题整理一下吧。

互联网中的数据量通常会很大,比如埋点数据。。。因此在日常数据处理中就会遇到数据倾斜的问题,就是那种跑半天跑不出数据或者reduce阶段卡在99%的那种情况。。。今天来说一下日常遇到数据倾斜的解决办法!

本文将从一下几个方面进行总结:

1、去重问题:

     1.1  union-union all(子查询实现job的并行运算)

           union 和union all的区别就是union具有去重的功能,且是一个全局的去重的过程,因为去重就会涉及到一个排序的问题,因此在使用union时效率会比较低。

     1.2  distinct 和 group by 

       在日常使用中,不建议使用distinct 进行去重,特别针对于埋点数据,通常会用group by进行替代。还有一中场景通常是要进行去重然后进行计数,比如计算UV等数据,可以和union 和group by 结合使用。

案例:

--统计多个页面汇总的UV
SELECT COUNT(*)  AS  UV
  FROM 
   (   SELECT clientcode
         FROM 
          (   SELECT clientcode FROM dwhtl.maidian_page_data_01
               UNION ALL
              SELECT clientcode FROM dwhtl.maidian_page_data_02
          ) a 
         GROUP BY clientcode 
    ) a        

 上面的代码写法,在MapReduce阶段,group by已经对clientcode进行去重了,最后统计的就直接是去重后的数据。但是如果直接用count(distinct clientcode)的话,会有一个全局排序的过程,效率会很低。

2、JOB数的控制

应尽可能的减少job数而提高查询速度。

   2.1 使用union all减少job数

        如果union all查询语句中有group by ,它仍然是多个job,并没有达到优化的效果。

SELECT pagecode
      ,COUNT(*)  AS  num
  FROM 
   (   SELECT pagecode,clientcode  FROM dwhtl.maidian_data_page_01
        UNION ALL
       SELECT pagecode,clientcode  FROM dwhtl.maidian_data_page_02
        UNION ALL
       SELECT pagecode,clientcode  FROM dwhtl.maidian_data_page_03
   ) a
 GROUP BY pagecode
       

上述写法,只有一个job,因为在map阶段,已经融合了所有的数据。   

2.2  多表连接时,同join条件,也会减少job数。

即在多张表进行连接时,主表的和多个副表的连接条件相同时,只用一个job就解决了。

2.3   设置合理的map reduce的task数,能有效提升性能。

具体参数,见https://blog.csdn.net/weixin_37536446/article/details/82462742

3、数据值&数据类型的问题

3.1 NULL值问题

      在实际使用中,如果null值较多,值为null的会人道一个ruduce中进行处理,导致这一个的ruduce处理的量过大,产生数据倾斜。注:如果这个字段不是join、group by 的条件,就不会因为它而产生倾斜。

解决办法1:将任务拆开,即先将连接的字段值为null的过滤掉(限制条件is not null),然后用union all将过滤掉的数据(限制条件is null)合到一起。

解决办法2:利用随机函数,将为null的数据随机分布到不同的reduce中。因为空值不参与关联,即使分到不同 的 Reduce 上,也不会影响最终的结果。即在连接时,连接条件如下:

                   ON CASE WHEN a.user_id IS NULL THEN CONCAT(‘dp_hive’,RAND()) ELSE a.user_id END =b.user_id;

  3.2  数据类型不一致。

  在进行连接操作时,将所连接的数据类型进行转换,比如: on a.date = cast(b.date as string)

3.3  业务本身的数据导致

       比如在全国的流量时,北京的人流量是其他地方的综合还要多,这个时候如果按照地区进行统计就会产生数据倾斜的问题。

解决办法:添加job数,增加随机列。

4、hive策略优化

在写SQL时,应尽量避免不必要的数据读入,比如字段、分区等。

4.1 列裁剪

Hive 在读数据的时候,只读取查询中所需要用到的列,而忽略其它列,这能够有效的节省了读取开销,中间表存储开销和数据整合开销。

裁剪所对应的参数项为:hive.optimize.cp=true(默认值为真)

4.2 分区裁剪

 在查询时,避免读取全部的分区,只读取自己想要的分区数据。

分区参数为:hive.optimize.pruner=true(默认值为真)

4.3  JOIN操作

     SQL中带有 join 操作的代码语句时,应该将条目少的表/子查询放在 Join 操作符的左边。 因为在 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,载入条目较少的表 可以有效减少 OOM(out of memory)即内存溢出。

5、控制任务数

5.1  map控制(太少了会造成并发数,太多了会浪费大量的内存。)

1、每个map最大输入大小:SET mapred.max.split.size = 256000000;

即(256M),现在假如输入有1024M,这样就会被拆成4个map,1028M则会有5个map

2、一个节点上split的至少的大小:SET mapred.min.split.size.per.node=100000000(100M)

4是进行小文件合并,2是判断把怎么样的小文件合并。

3、执行map前进行小文件合并:

SET hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

5.2  reduce控制

1、每个reduce处理的数据量

SET hive.exec.reducers.bytes.per.reducer = 500000000;

即(500M)一般情况下设置这一个就ok了

2、制定reduce数量

SET mapred.reduce.tasks = 20;

3、reduce输出文件数

在Map-only的任务结束时合并小文件

SET hive.merge.mapfiles = true

在Map-Reduce的任务结束时合并小文件

SET hive.merge.mapredfiles = true

合并文件的大小

SET hive.merge.size.per.task = 256*1000*100

输出文件的平均值大小小于该值时,启动一个独立的map-reduce任务进行文件合并

SET hive.merge.smallfiles.avgsize = 16000000(16M)

 

以上就是在工作中遇到的数据倾斜问题,也给出了解决方法,欢迎相互交流~

你可能感兴趣的:(hive)