hive调优_如何解决数据倾斜问题

如何解决数据倾斜问题

1 Join数据倾斜

1.1解决方案一

Map Join (默认开启), 
Bucket Map Join(默认关闭,条件是分桶表,且数量是倍数关系) , 
SMB Join(条件是分桶表,且桶数量必须一致,插入数据的时候要排序)
    
注意:  
   通过 Map Join,Bucket Map Join,SMB Join 来解决数据倾斜, 但是 这种操作是存在使用条件的, 如果无法满足这些条件,  无法使用 这种处理方案

1.2解决方案二

思路:  将那些产生倾斜的key和对应v2的数据, 从当前这个MR中移出去, 单独找一个MR来处理即可, 处理后, 和之前的MR进行汇总结果即可

关键问题:  如何找到那些存在倾斜的key呢?  特点: 这个key数据有很多

1.运行期处理方案:
    思路: 在执行MR的时候, 会动态统计每一个 k2的值出现重复的次数, 当这个重复的次数达到一定的阈值后, 认为当前这个k2的数据存在数据倾斜, 自动将其剔除, 交由给一个单独的MR来处理即可,两个MR处理完成后, 将结果基于union all 合并在一起即可
    
    实操:  
        set hive.optimize.skewjoin=true;  -- 开启运行期处理倾斜参数默认false
        set hive.skewjoin.key=100000;   -- 阈值,  此参数在实际生产环境中, 需要调整在一个合理的值(否则极易导致大量的key都是倾斜的),默认100000
            判断依据: 查看 join的 字段 对应重复的数量有多少个, 然后选择一个合理值
              比如判断:  id为 1  大概有 100w  id为 2 88w  id 为 3 大概有 500w   设置阈值为 大于500w次数据
               或者: 总数量大量1000w, 然后共有 1000个班级, 平均下来每个班级数量大概在 1w条, 设置阈值:  大于 3w条 ~5w条范围 (超过3~5倍才认为倾斜)
        
    
    适用于: 并不清楚那个key容易产生倾斜, 此时交由系统来动态检测

2.编译期处理方案: 
    思路1:  在创建这个表的时候, 我们就可以预知到后续插入到这个表中数据, 那些key的值会产生倾斜, 在建表的时候, 将其提前配置设置好即可, 在后续运行的时候, 程序会自动将设置的key的数据单独找一个MR来进行处理即可, 处理完成后, 再和原有结果进行union all 合并操作
    
    实操1:  
        set hive.optimize.skewjoin.compiletime=true;  -- 开启编译期处理倾斜参数
        
        CREATE TABLE list_bucket_single (key STRING, value STRING) 
        -- 倾斜的字段和需要拆分的key值 
        SKEWED BY (key) ON (1,5,6) 
        -- 为倾斜值创建子目录单独存放 
        [STORED AS DIRECTORIES];
        
      思路2: 大量的key可以拼接rand()  
      实操2: 举例: 如果大量相同的男,可以拼接随机数: concat('男',rand())

    适用于:  提前知道那些key存在倾斜
    
在实际生产环境中, 应该使用那种方式呢?   两种方式都会使用的
    一般来说, 会将两个都开启, 编译期的明确在编译期将其设置好, 编译期不清楚, 通过运行期动态捕获即可

底层union all 优化方案

 说明: 不管是运行期 还是编译期的join倾斜解决, 最终都会运行多个MR, 将多个MR结果通过union all 进行汇总, union all也是需要单独一个MR来处理
    
解决方案: 
        让每一个MR在运行完成后, 直接将结果输出到目的地即可, 默认 是各个MR将结果输出临时目录, 通过 union all 合并到最终目的地
         
        开启此参数即可: 
        set hive.optimize.union.remove=true;

2 group by 数据倾斜

为什么在group by 的时候, 可能会出现倾斜的问题呢?

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

MAP 阶段: 假设Map阶段跑了二个MapTask

    mapTask1:
        k2          v2
        c01        {s01       张三     c01}
        c02        {s02       李四     c02}
        c01        {s03       王五     c01}
        c03        {s04       赵六     c03}
    mapTask2:
        k2          v2
        c02        {s05       田七     c02}
        c01        {s06       周八     c01}
        c01        {s07       李九     c01}
        c04        {s08       老王     c04}



reduce阶段: 假设reduceTask有二个

    reduceTask1: 接收 c01 和 c02的数据
      接收数据
         k2        v2
        c01        {s01       张三     c01}
        c02        {s02       李四     c02}
        c01        {s03       王五     c01}
        c02        {s05       田七     c02}
        c01        {s06       周八     c01}
        c01        {s07       李九     c01}

      分组后:
        c01      [{s01       张三     c01},{s03       王五     c01},{s06       周八     c01},{s07       李九     c01}]
        c02      [{s02       李四     c02},{s05       田七     c02}]

      结果数据: 
        c01     4
        c02     2

    reduceTask2: 接收 c03 和 c04的数据
      接收数据
         k2        v2
        c03        {s04       赵六     c03}
        c04        {s08       老王     c04}

      分组后:
        c03        [{s04       赵六     c03}]
        c04        [{s08       老王     c04}]

      结果数据:
        c03     1
        c04     1

在以上整个计算流程中, 发现 其中一个reduce接收到的数据量比另一个reduce接收的数据量要多的多, 认为出现了数据倾斜的问题, 所以group by 也有可能产生数据倾斜

思考: 如何解决group by的数据倾斜呢?

2.1解决方案一

MR的 combiner(规约, 提前聚合) 减少数据达到reduce数量, 从而减轻倾斜问题

默认开启 set hive.map.aggr=true;

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

MAP 阶段: 假设Map阶段跑了二个MapTask
    mapTask1:
        k2          v2
        c01        {s01       张三     c01}
        c02        {s02       李四     c02}
        c01        {s03       王五     c01}
        c03        {s04       赵六     c03}
    规约(提前聚合)操作: 处理逻辑与reduce处理逻辑一致
      分组: 
         c01    [{s01       张三     c01},{s03       王五     c01}]  
         c02    [{s02       李四     c02}]
         c03    [{s04       赵六     c03}]
      提前聚合得出结果:
          c01     2
          c02     1
          c03     1
    mapTask2:
        k2          v2
        c02        {s05       田七     c02}
        c01        {s06       周八     c01}
        c01        {s07       李九     c01}
        c04        {s08       老王     c04}
    规约(提前聚合)操作: 处理逻辑与reduce处理逻辑一致
      分组: 
         c01    [{s06       周八     c01},{s07       李九     c01}]  
         c02    [{s05       田七     c02}]
         c04    [{s08       老王     c04}]
     提前聚合得出结果:
          c01     2
          c02     1
          c04     1


reduce阶段: 假设reduceTask有二个
    reduceTask1: 接收 c01 和 c02的数据
      接收数据
         k2        v2
         c01       2
         c02       1
         c01       2
         c02       1    
      分组后:
        c01      [2,2]
        c02      [1,1]  
      结果数据: 
        c01     4
        c02     2 
    reduceTask2: 接收 c03 和 c04的数据
      接收数据
         k2        v2
         c03       1
         c04       1 
      分组后:
        c03        [1]
        c04        [1]
      结果数据:
        c03     1
        c04     1  
  
 通过规约来解决数据倾斜, 处理完成后, 发现 两个reduce中从原来相差 3倍, 变更为相差 2倍, 减轻了数据倾斜问题
 
 
 如何配置呢? 
     只需要在HIVE中开启combiner提前聚合配置参数即可:  
         set hive.map.aggr=true;

解决方案二

假设目前有这么一个表:  

sid       sname    cid
s01       张三     c01
s02       李四     c02
s03       王五     c01
s04       赵六     c03
s05       田七     c02
s06       周八     c01
s07       李九     c01
s08       老王     c04

需求: 请计算每个班级有多少个人
select  cid,count(1) as total  from  stu  group by  cid;

翻译后MR是如何处理SQL呢?

第一个MR的操作: 对数据进行打散
Map 阶段:  假设运行了两个MapTask
    mapTask1:
        k2          v2
        c01        {s01       张三     c01}
        c02        {s02       李四     c02}
        c01        {s03       王五     c01}
        c03        {s04       赵六     c03}
    mapTask2:
        k2          v2
        c02        {s05       田七     c02}
        c01        {s06       周八     c01}
        c01        {s07       李九     c01}
        c04        {s08       老王     c04}  

mapTask执行完成后, 在进行分发数据到达reduce, 默认情况下将相同k2的数据发往同一个reduce, 目前采用方案为随机分发, 保证每一个reduce拿到相等数量的数据信息(负载过程, 让每一个reduce接收到相同数量的数据)

reduce阶段: 假设有两个reduceTask

    reduceTask1:
        接收到数据:  
            c01        {s01       张三     c01}
            c01        {s03       王五     c01}
            c01        {s06       周八     c01}
            c01        {s07       李九     c01}
        分组操作: 
            c01    [{s01       张三     c01},{s03       王五     c01},{s06       周八     c01},{s07       李九     c01}]     
        输出结果: 
            c01     4
    reduceTask2:
        接收到数据:
            c03        {s04       赵六     c03}
            c02        {s05       田七     c02}
            c02        {s02       李四     c02}
            c04        {s08       老王     c04}

        分组操作: 
            c03        [{s04       赵六     c03}]
            c02        [{s02       李四     c02},{s05       田七     c02}]
            c04        [{s08       老王     c04}]

        输出结果:
            c02     2
            c03     1
            c04     1
            
负载均衡解决:
第一个MR执行完成了, 随机打乱分配,假设每个reduce都接收到四条数据, 自然也就不存在数据倾斜的问题了

第二个MR进行处理:  严格按照相同k2发往同一个reduce

Map 阶段:  假设有二个mapTask
    mapTask1:  
        k2      v2
        c01     2
        c02     2
    mapTask2:
        k2      v2
        c01     2
        c03     1
        c04     1
reduce阶段:   假设有两个reduce
    reduceTask1: 接收 c01 和 c02 数据
      接收数据:  
         k2     v2
         c01     4
         c02     2
      结果:
         c01    4
         c02    2
    reduceTask2: 接收 c03 和c04
      接收数据:  
         k2     v2
         c03     1
         c04     1 
      结果:
         c03     1
         c04     1


通过负载均衡方式来解决数据倾斜, 同样也可以减轻数据倾斜的压力


细细发现, 方案一 和 方案二, 是有类似之处的, 方案一, 让每一个mapTask内部进行提前聚合, 然后到达reduce进行汇总合并得出结构, 方案二: 让第一个MR进行打散并对数据进行聚合计算 得出局部结果, 然后让第二个MR进行最终聚合计算操作, 得出最终结果


说明: 方案二, 比方案一, 更能彻底解决数据倾斜问题, 因为其处理数据范围更大, 整个整个数据集来处理, 而方案一, 只是每个MapTask处理, 仅仅局部处理

如何使用方案二: 
    只需要开启负载均衡的HIVE参数配置即可:
        set hive.groupby.skewindata=true;

这两种方式:  建议在生产中, 优先使用第一种, 如果第一种无法解决, 尝试使用第二种解决


注意事项:   使用第二种负载均衡的解决group by 的数据倾斜, 一定要注意, SQL语句中不能出现多次  distinct操作, 否则 HIVE会直接报错的
    错误信息: 
        Error in semantic analysis: DISTINCT on different columns not supported with skew in data.
    比如说: 
        SELECT ip, count(DISTINCT uid), count(DISTINCT uname) FROMlog GROUP BY ip   此操作就直接报错了,只能使用方案一解决数据倾斜

倾斜的参数配置开启条件, 一定是出现了数据倾斜的问题, 如果没有出现 不需要开启的

3 查找是否倾斜

思考: 如何才能知道发生了数据倾斜呢?

 倾斜发生后, 出现的问题, 程序迟迟无法结束, 或者说翻译的MR中reduceTask有多个, 大部分的reduceTask都执行完成了, 只有其中一个或者几个没有执行完成, 此时认为发生了数据倾斜
    
    
    关键点: 如何查看每一个reduceTask执行时间

方式: 通过Yarn查看(运行过程中) 或者 jobhistory查看(已经结束的程序) (此操作, 只能在本地演示查看, 云端环境没有开启yarn端口, 无法查看的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值