数据倾斜的原因表现以及解决方法 -c

数据倾斜

如果有10亿数据,一台电脑可能要10小时,现在集群有10台,可能1小时就够了,但是有可能大量的数据集中到一台或几台上,要5小时,发生了数据倾斜,例如:
公司一:总用户量1000万,5台64G内存的服务器。
公司二:总用户量10亿,1000台64G内存的服务器。
1.公司一的数据分析师在做join的时候发生了数据倾斜,会导致有几百万用户的相关数据集中到了一台服务器上,几百万的用户数据,说大也不大,正常字段量的数据的话64G还是能轻松处理掉的。
2.公司二的数据分析师在做join的时候也发生了数据倾斜,可能会有1个亿的用户相关数据集中到了一台机器上了(相信我,这很常见)。这时候一台机器就很难搞定了,最后会很难算出结果。

1.数据倾斜表现

1.1 hadoop中的数据倾斜表现:

  • 有一个多几个Reduce卡住,卡在99.99%,一直不能结束。
  • 各种container报错OOM
  • 异常的Reducer读写的数据量极大,至少远远超过其它正常的Reducer
  • 伴随着数据倾斜,会出现任务被kill等各种诡异的表现。

1.2 hive中数据倾斜
任务进度长时间维持在 99%或者 100%的附近,查看任务监控页面,发现只有少量 reduce子任务未完成,因为其处理的数据量和其他的 reduce 差异过大。单一 reduce 处理的记录数和平均记录数相差太大,通常达到好几倍之多,最长时间远大于平均时长。
一般都发生在Sql中group by和join on上,而且和数据逻辑绑定比较深。

1.3 Spark中的数据倾斜
Spark中的数据倾斜,包括Spark Streaming和Spark Sql,表现主要有下面几种:

  • Executor lost,OOM,Shuffle过程出错;
  • Driver OOM;
  • 单个Executor执行时间特别久,整体任务卡在某个阶段不能结束;
  • 正常运行的任务突然失败;

2.数据倾斜产生原因

我们以Spark和Hive的使用场景为例。
他们在做数据运算的时候会涉及到,count distinct、group by、join on等操作,这些都会触发Shuffle动作。一旦触发Shuffle,所有相同key的值就会被拉到一个或几个Reducer节点上,容易发生单点计算问题,导致数据倾斜。
一般来说,数据倾斜原因有以下几方面:
2.1 key分布不均匀
在这里插入图片描述

2.2 建表时考虑不周
我们举一个例子,就说数据默认值的设计吧,假设我们有两张表:
user(用户信息表):userid,register_ip
ip(IP表):ip,register_user_cnt
这可能是两个不同的人开发的数据表。如果我们的数据规范不太完善的话,会出现一种情况:
user表中的register_ip字段,如果获取不到这个信息,我们默认为null;
但是在ip表中,我们在统计这个值的时候,为了方便,我们把获取不到ip的用户,统一认为他们的ip为0。
两边其实都没有错的,但是一旦我们做关联了,这个任务会在做关联的阶段,也就是sql的on的阶段卡死。
2.3业务数据本身的特, 业务数据激增
比如订单场景,我们在某一天在北京和上海两个城市多了强力的推广,结果可能是这两个城市的订单量增长了10000%,其余城市的数据量不变。
然后我们要统计不同城市的订单情况,这样,一做group操作,可能直接就数据倾斜了。

2.4 shuffle阶段出现数据倾斜
shuffle是按照key,来进行values的数据的输出、拉取和聚合的,一旦发生shuffle,所有相同key的值就会拉到一个或几个节点上,个别key对应的数据比较多,就容易发生单个节点处理数据量爆增的情况。
2.5key分布不均匀
存在大量相同值的数据
存在大量异常值或者空值

2.6某些SQL语句本身就有数据倾斜

  • 两个表中关联字段存在大量空值(解决方法:去除或者加随机数),或是关联字段的数据不统一(解决方法:把数字类型转为字符串类型,统一大小写)
  • join 一个key集中的小表 (解决方法:reduce join 改成 map join)
  • group by维度过小 某值的数量过多 (解决方法:两阶段聚合,放粗粒度)
  • count distinct 某特殊值过多 (解决方法:先用group by)
  • 数据频率倾斜——某一个区域的数据量要远远大于其他区域。
  • 数据大小倾斜——部分记录的大小远远大于平均值。

3.解决数据倾斜思路

以下解决思路引用自
https://blog.csdn.net/qq_30031221/article/details/114378730

3.1聚合类group by操作,发生数据倾斜

  • map段部分聚合
    • 开启Map端聚合参数设置set hive.map.aggr=true
    • 在Map端进行聚合操作的条目数目set hive.grouby.mapaggr.checkinterval=100000
    • 有数据倾斜的时候进行负载均衡(默认是false)set hive.groupby.skewindata = true
  • 阶段拆分-两阶段聚合 需要聚合的key前加一个随机数的前后缀,这样就均匀了,之后再按照原始的key聚合一次

生- 成的查询计划有两 个 MapReduce 任务。在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个 reduce 做部分聚合操作,并输出结果。相同的 Group By Key 有可 能分发到不同的 reduce 中,从而达到负载均衡的目的;第二个 MapReduce 任务再根据预处 理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作。

假设 key = 水果
select count(substr(a.key,1,2)) as key
from(
	select concat(key,'_',cast(round(10*rand())+1 as string)) tmp
	from table
	group by tmp
)a
group by key

3.2 空值产生的数据倾斜

1.在查询的时候,过滤掉所有为NULL的数据,比如:
SELECT * FROM log a
JOIN bmw_users b ON a.user_id IS NOT NULL AND a.user_id = b.user_id
UNION ALL
SELECT *FROM log a WHERE a.user_id IS NULL;

2.查询出空值并给其赋上随机数,避免了key值为空(数据倾斜中常用的一种技巧)
SELECT *FROM log a
LEFT JOIN bmw_users b ON 
CASE WHEN a.user_id IS NULL THEN concat(‘dp_hive’, rand()) ELSE a.user_id END = b.user_id;

3.3 Reduce join 改为Map join

  • 适用于小表和大表 join,将较小RDD中的数据直接通过collect算子拉取到Driver端的内存中来,然后对其创建一个Broadcast变量;接着对另外RDD执行map类算子,在算子函数内,从Broadcast变量中获取较小RDD 的全量数据,与当前RDD的每一条数据按照连接key进行比对,如果连接key相同的话,那么就将两个RDD的数据用你需要的方式连接起来。
  • 设置自动选择MapJoin set hive.auto.convert.join = true;默认为true
  • reduce join: 先将所有相同的key,对应的values,汇聚到一个task中,然后再进行join。
  • map reduce:broadcast出去那个小表的数据以后,就会在每个executor的block manager中都驻留一份+map算子来实现与join同样的效果。不会发生shuffe,从根本上杜绝了join操作可能导致的数据倾斜的问题;

排序选择

  • cluster by: 对同一字段分桶并排序,不能和sort by连用;
  • distribute by + sort by: 分桶,保证同一字段值只存在一个结果文件当中,结合sort by 保证每个reduceTask结果有序;
  • sort by: 单机排序,单个reduce结果有序
  • order by:全局排序,缺陷是只能使用一个reduce
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值