【Hive】hive 数据倾斜、优化策略、hive执行过程、垃圾回收

1. 数据倾斜

1.1 什么是数据倾斜?

  • 由于数据分布不均匀,造成数据大量的集中到一点,造成数据热点

  • Hadoop 框架的特性

    • 不怕数据大,怕数据倾斜
    • Jobs 数比较多的作业运行效率相对比较低,如子查询比较多
    • sum,count,max,min 等聚集函数,通常不会有数据倾斜问题
  • 主要表现:
    任务进度长时间维持在 99%或者 100%的附近,查看任务监控页面,发现只有少量 reduce子任务未完成,因为其处理的数据量和其他的 reduce 差异过大。
    单一 reduce 处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大
    于平均时长。

1.2 容易数据倾斜情况

操作 情形 后果
join 其中一个表小
但是key集中
分发到某一个或几个reduce中的数据远高于平均值
join 大表与大表,但是分桶的判断字段0或空值过多 这些空值由一个reduce处理,非常慢
group by group by维度过小,某值的数据过多 处理某值的reduce非常耗时
count distinct 某特殊值过多 处理此特殊值的reduce耗时
  • reduce join hive执行join的时候如果执行的是reduce join极易数据倾斜的
  • group by 不和聚集函数搭配使用的时候
    select count(*) from course; 全局计数 (一个reduce task中)
  • count(distinct),在数据量大的情况下,容易数据倾斜,因为 count(distinct)是按 group
    by 字段分组,按 distinct 字段排序
  • 小表关联超大表 join

1.3 产生数据倾斜的原因

  • key 分布不均匀
  • 业务数据本身的特性
  • 建表考虑不周全
  • 某些 HQL 语句本身就存在数据倾斜

1.4 不会产生数据倾斜的情况

  1. 不执行MR任务的情况
    fetch过程不会转MR
    配置参数:

    <property>
       <name>hive.fetch.task.conversion</name>
       <value>more</value>
       <description>
         可取值[none, minimal, more].
         Some select queries can be converted to single FETCH task minimizing latency.
         Currently the query should be single sourced not having any subquery and should not have
         any aggregations or distincts (which incurs RS), lateral views and joins.
         0. none : disable hive.fetch.task.conversion
         1. minimal : SELECT *, FILTER on partition columns, LIMIT only
    		也就是:select * ,过滤条件是分区字段,limit   
         2. more    : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
    		也就是:select 所有字段,按照所有字段过滤,limit
       </description>
     </property>
      
    
  2. group by和聚合函数(sum count max min)一起使用
    group by和以上的聚合函数一起使用的时候会默认在map端执行一次combiner(局部聚合:减少reducetask的数据量,这个时候reduce端接受的数据就会大大减少 一般不会出现数据倾斜
    select id,count(*) from course group by id;

  3. map join
    mapjoin reducejoin 优缺点

1.5 业务场景

1.5.1 空值产生的数据倾斜

场景描述:

user	用户信息表  userid  一个用户注册这个表就会多一条数据 userid!=null
log		日志信息表  userid  用户只要有一个行为就多一条数据  如果未登录用户操作 userid=null  这种数据数据特别多5T

操作:

select * from user a join log b on a.userid=b.userid;

map-key: userid
	userid 大量的null值   这些null值最终都会到一个reducetask中
	就会造成有null的这个reducetask的数据量很大
	100reducetask
	99reducetask   0.05	t   
	1reduce    5t   
	
	reducetask    99%    
	reducetask    99% 
	reducetask    99% 

解决方案:
方案一:null值不参与关联

select 
* 
from user a join 
(select * from log where userid is not null) b 
on a.userid=b.userid;
--需要null的数据
select 
* 
from user a join 
(select * from log where userid is not null) b 
on a.userid=b.userid 
union all 
select * from log where userid is null;

方案二:赋予空值新的key值

--所有的null值全部到一个reducetask中   进行关联的时候  null值分开 null---变身
--null123.hash%reduce  null456  null112
select 
* 
from user a 
join log b 
on case when b.userid is null then concat_ws(b.userid,cast(rand()*1000 as int)) else b.userid end = a.userid;

总结:
方法 2 比方法 1 效率更好,不但 IO 少了,而且作业数也少了,
方案 1 中,log 表读了两次,jobs 肯定是 2,而方案 2 是 1。
这个优化适合无效 id(比如-99,’’,null)产生的数据倾斜,把空值的 key 变成一个字符串加上一个随机数,就能把造成数据倾斜的数据分到不同的 reduce 上解决数据倾斜的问题

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

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

场景说明:

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

解决方案:
把数字类型 id 转换成 string 类型的 id

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

1.5.1 大小表关联查询产生数据倾斜

  1. 小 或 小 小 关联(小表<=23.8M)
    在hive中默认的是map端的join,小表不得超过23.8M左右

    <property>
    	<name>hive.auto.convert.join</name>
    	<value>true</value>
    	<description>Whether Hive enables the optimization about converting common join into mapjoin based on the input file size
    	指定是否启动mapjoin
    	</description>
    	</property>
    	
    <property>
    	<name>hive.mapjoin.smalltable.filesize</name>
    	<value>25000000</value>
    	<description>
    	  The threshold for the input file size of the small tables; if the file size is smaller 
    	  than this threshold, it will try to convert the common join into map join
    	  mapjoin对于小表的大小的限定  默认大小不得超过23.8M左右
    	  较小表大小不超过23.8M 执行的都是mapjoin
    	</description>
    </property>
    	
    
  2. 大* 中 (中表:超过23.8M) 放在缓存中足够的
    默认执行的是reducejoin(容易产生数据倾斜的)
    强制执行mapjoin /+mapjoin(需要放在缓存中的中表)/

    -- user  1T   log 300M
    select 
    /*+mapjoin(a)*/ 
    * 
    from log a join user b on a.userid=b.userid;
    --执行的仍然是mapjoin
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值