如何处理hive的数据倾斜?

hive的数据倾斜

  • 出现倾斜的根本原因:
  • 一 数据倾斜处理
    • 1 使用map join/bucket map join/SMB map join解决
      • 小表 join 大表(Map join)
      • 中型表 join大表 (bucket map join)
      • 大表 join大表(SMB map join)
    • 2 单独找MR处理
    • 3 union all 的优化
  • 二 group by数据倾斜
    • 为啥会倾斜呢 ?
    • 解决一 基于MR的 combiner(归约) (提前在map端提前完成聚合操作)
    • 解决二 负载均衡(跑两个MR,)

出现倾斜的根本原因:

在reduce中,某一个或者某几个的分组k2对应的value的数据比较多.从而引起数据倾斜问题.

一 数据倾斜处理

1 使用map join/bucket map join/SMB map join解决

q: 为什么传统默认join效率低?

默认执行的时候 .执行join的sql. 走MR的时候 最终是在 reduce端进行join操作 .
出现问题:
1 所有的join连接工作 都是交给reduce端.压力比较大.
2 可能会出现数据倾斜问题
解决: 变为map join

map join: 将核心join操作.都集中在map端操作.而map数量是有读取文件的切片决定的,
  	会保证每一个maptask的数量最基本是差不多.不会导致数据倾斜问题.map的数量会随着
  	读取文件数据量增大而增多.依次不断提升MR的执行效率.
弊端: 
  1 比较耗费内粗
  2 要求整个join中 必须有小表 
使用条件:
  1 set hive.auto.convert.join=true:--开启map join 的支持.默认就是true
  2 set hive.auto.convert.join.noconditionaltask.size=512000000 默认为 20971520(20M)

小表 join 大表(Map join)

使用条件:
1 set hive.auto.convert.join=true;  -- 开启map join的支持, 默认就是true
2 set hive.auto.convert.join.noconditionaltask.size=512000000 默认为 20971520 (20M)

对表类型没有要求

中型表 join大表 (bucket map join)

使用条件:
1 两个表必须是分桶表 
2 开始bucket map join 支持 : set hive.optimize.bucketmapjoin = true
3 一个表的分桶表的数量是另一个表的分桶表数量的整数倍
4 bucket列必须是 join 的列
5 必须应用在map join 场景中

大表 join大表(SMB map join)

SMB: sort merge bucket

使用条件:
1 两个表必须是分桶表 
2 开始SMB map join 支持
 	set hive.optimize.bucketmapjoin = true;  -- 开启 bucket map join
	set hive.auto.convert.sortmerge.join=true; -- 开启 SBM join支持
	set hive.auto.convert.sortmerge.join.noconditionaltask=true;  -- 开启 SBM join支持
	set hive.optimize.bucketmapjoin.sortedmerge = true  -- 自动尝试开启 SMB join
3 两个表分桶表必须是一致的 
4 bucket 列必须是join的列 同时必须保证分桶字段进行排序操作 
	set hive.enforce.sorting=true; --开始强制排序 
5 必须应用在 map join 的场景中

如果无法满足map join 的条件 则以下:

2 单独找MR处理

	思路:  将那些产生倾斜的k2和对应value数据, 从当前这个MR移植出去, 单独找一个MR来处理即可, 处理后, 和之前MR的汇总结果即可
	关键问题: 如何找出那些存在倾斜的k2数据
	
	运行期处理方案:
		思路: 在执行MR的时候, 会动态统计每一个k2的值出现的重复的数量, 当这个重复的数量达到一定阈值后, 认为当前这个k2的数据存在数据倾斜, 自动将其剔除, 交由给一个单独的MR来处理即可, 两个MR处理完成后, 将结果, 基于union all 合并在一起即可
		实操 :
			set hive.optimize.skewjoin=true;
			set hive.skewjoin.key=100000; -- 实际需要进行调整在合理的值
		适用于: 并不清楚那个key容易产生倾斜, 此时可以交由系统来动态检测
	
	编译期处理方案: 
		思路: 在创建这个表的时候,我们就可以预知到后续插入到这个表中, 那些key的值会产生倾斜, 在建表的时候, 将其提前配置设置好即可, 在后续运行的时候, 程序会自动将设置的k2的值数据单独找一个MR来进行单独的处理操作, 处理后, 再和原有MR进行union all的合并操作
		
		实操:
			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];
            
一般来说, 会将两个都开启, 编译期的明确在编译期将其设置好, 编译期不清楚, 通过 运行期动态捕获即可

3 union all 的优化

	说明: 不管是运行期, 还是编译期的join倾斜解决, 最终都会运行多个MR , 最终将多个MR的结果, 通过union all进行汇总, union all也是单独需要一个MR来运行的

	解决方案: 
		让每一个MR在运行完成后, 直接将结果输出到目的地即可, 默认是输出到临时文件目录下, 通过union all合并到最终目的地
		set hive.optimize.union.remove=true;

二 group by数据倾斜

为啥会倾斜呢 ?

假设目前有这么一个表:  

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

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

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

map 阶段:

mapTask 1
	k2      v2
	c01     {s01 张三 c01}
	c02     {s02 李四 c02}
	c01     {s03 王五 c01}
	c03     {s04 赵六 c03}

mapTask 2
    k2      v2
    c02     {s05 田七 c02}
	c01     {s06 周八 c01}
	c01     {s07 李九 c01}
	c03     {s08 老夯 c03}

reduce  阶段

reduceTask 1 :   接收 c01  和 c03
  接收到的数据:
    k2      v2
    c01     {s01 张三 c01} 
	c01     {s03 王五 c01}
	c03     {s04 赵六 c03}
	c01     {s06 周八 c01}
	c01     {s07 李九 c01}
    c03     {s08 老夯 c03}
  分组后:  
    c01   [{s01 张三 c01},{s03 王五 c01},{s06 周八 c01},{s07 李九 c01}]
    c03   [{s04 赵六 c03},{s08 老夯 c03}]
  结果:
    c01   4
    c03   2
reduceTask 2 :  接收 c02 
   接收到的数据:
     k2     v2
     c02     {s02 李四 c02} 
     c02     {s05 田七 c02}
   分组后:
     c02   [{s02 李四 c02} , {s05 田七 c02}]
   结果:
     c02   2
以上整个计算过程中, 发现 其中一个reduce接收到的数据量比另一个reduce接收的数据量要多得多, 认为出现了数据倾斜问题


此时 reducetask的数据 为 6:2

解决一 基于MR的 combiner(归约) (提前在map端提前完成聚合操作)

解决方案一: 基于MR的combiner(规约)减轻数据倾斜问题   (小combiner)  在map端提前完成聚合操作

假设目前有这么一个表:  

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

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

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

map 阶段:

mapTask 1
	k2      v2
	c01     {s01 张三 c01}
	c02     {s02 李四 c02}
	c01     {s03 王五 c01}
	c03     {s04 赵六 c03}
规约操作: 跟reduce的操作是一致的
  输出:
	k2      v2
	c01     2
	c02     1
	c03     1

mapTask 2
    k2      v2
    c02     {s05 田七 c02}
	c01     {s06 周八 c01}
	c01     {s07 李九 c01}
	c03     {s08 老夯 c03}
规约操作: 跟reduce的操作是一致的
   输出:
     k2      v2
     c02      1
     c01      2
     c03      1

reduce  阶段

reduceTask 1 :  接收 c01  和 c03
   接收到数据:
      k2     v2
      c01     2
      c03     1
      c01     2
      c03     1
   分组处理:
      c01    [2,2]
      c03    [1,1]
   结果:
      c01    4
      c03    2
reduceTask 2 : 接收 c02
   接收到数据:
      k2     v2
      c02     1
      c02     1
   分组后:
       c02  [1,1]
   结果:
       c02   2


通过规约来解决数据倾斜, 发现处理后, 两个reduce中从原来(6:2)相差3, 变更为相差2(4:2) , 减轻了数据倾斜问题

如何配置呢? 
	只需要在hive中开启combiner使用配置即可:
		set hive.map.aggr=true;

解决二 负载均衡(跑两个MR,)

解决方案一: 基于MR的combiner(规约)减轻数据倾斜问题   (小combiner)

假设目前有这么一个表:  

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

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

翻译后MR是如何处理SQL的呢? 
第一个MR的操作: 
map 阶段:

mapTask 1
	k2      v2
	c01     {s01 张三 c01}
	c02     {s02 李四 c02}
	c01     {s03 王五 c01}
	c03     {s04 赵六 c03}


mapTask 2
    k2      v2
    c02     {s05 田七 c02}
	c01     {s06 周八 c01}
	c01     {s07 李九 c01}
	c03     {s08 老夯 c03}

mapTask执行完成后, 在进行分发数据到达reduce, 默认将相同的k2的数据发往同一个reduce, 此时采用方案是随机分发, 保证每一个reduce拿到相等的数据条数即可


reduce阶段:  

reduceTask  1:
   接收到数据:
      k2          v2
      c01     {s01 张三 c01}
	  c02     {s02 李四 c02}
	  c01     {s03 王五 c01}
	  c01     {s06 周八 c01}
   分组操作: 
      c01     [{s01 张三 c01},{s03 王五 c01},{s06 周八 c01}]
      c02     [{s02 李四 c02}]
   结果: 
   	  c01     3
   	  c02     1
reduceTask  2: 
   接收到数据:
      k2          v2
      c03     {s04 赵六 c03}
	  c01     {s07 李九 c01}
	  c02     {s05 田七 c02}
	  c03     {s08 老夯 c03}
   分组操作:
      c03     [{s04 赵六 c03},{s08 老夯 c03}]
      c01     [{s07 李九 c01}]
      c02     [{s05 田七 c02}]
   结果:
      c03      2
      c01      1
      c02      1
第二个MR进行处理: 严格按照相同k2发往同一个reduce

map阶段: 

mapTask 1: 
   k2     v2
   c01     3
   c02     1
   c03     2
   c01     1
   c02     1
reduce阶段:  

reduceTask  1:  接收 c01 和 c03 
   接收到数据:
     k2      v2
     c01     3
     c01      1
     c03      2
   结果:
      c01   4
      c03   2
reduceTask  2:  接收 c02
   接收到的数据:
     k2      v2
     c02     1
     c02     1
   结果:
      c02    2

通过负载均衡来解决数据倾斜, 发现处理后, 两个reduce中从原来(6:2)相差3, 变更为相差1.5(3:2) , 减轻了数据倾斜问题


如何操作:
	只需要在hive中开启负载均衡使用配置即可:
		set hive.groupby.skewindata=true;

注意: 使用第二种负载均衡的解决group by的数据倾斜, 一定要注意, sql语句中不能出现多次 distinct操作, 否则hive直接报错
	错误信息:
		 Error in semantic analysis: DISTINCT on different columns notsupported with skew in data

你可能感兴趣的:(hadoop,hadoop)