解决数据倾斜的两篇文章

第一篇文章:

发现数据倾斜的时候,不要急于提高 executor 的资源,修改参数

或是修改程序,首先要检查数据本身,是否存在异常数据。

1、数据问题造成的数据倾斜

找出异常的 key

如果任务长时间卡在最后最后 1 个(几个)任务,首先要对 key 进行

抽样分析,判断是哪些 key 造成的。

选取 key,对数据进行抽样,统计出现的次数,根据出现次数大小排序取

出前几个。

比如:

df.select(“key”).sample(false,0.1).(k=>(k,1)).reduceBykey(+).ma

p(k=>(k._2,k._1)).sortByKey(false).take(10)

如果发现多数数据分布都较为平均,而个别数据比其他数据大上若

干个数量级,则说明发生了数据倾斜。

经过分析,倾斜的数据主要有以下三种情况:

1、null(空值)或是一些无意义的信息()之类的,大多是这个原因

引起。

2、无效数据,大量重复的测试数据或是对结果影响不大的有效数

据。

3、有效数据,业务导致的正常数据分布。

解决办法

第 1,2 种情况,直接对数据进行过滤即可(因为该数据对当前业

务不会产生影响)。

第 3 种情况则需要进行一些特殊操作,常见的有以下几种做法

(1) 隔离执行,将异常的 key 过滤出来单独处理,最后与正常数据

的处理结果进行 union 操作。

(2) 对 key 先添加随机值,进行操作后,去掉随机值,再进行一次

操作。

(3) 使用 reduceByKey 代替 groupByKey(reduceByKey 用于对每个

key 对应的多个 value 进行 merge 操作,最重要的是它能够在本地先进行

merge 操作,并且 merge 操作可以通过函数自定义.)(4) 使用 map join。

案例

如果使用 reduceByKey 因为数据倾斜造成运行失败的问题。具体操

作流程如下:

(1) 将原始的 key 转化为 key + 随机值(例如 Random.nextInt)

(2) 对数据进行 reduceByKey(func)

(3) 将 key + 随机值 转成 key

(4) 再对数据进行 reduceByKey(func)

案例操作流程分析:

假设说有倾斜的 Key,我们给所有的 Key 加上一个随机数,然后进

行 reduceByKey 操作;此时同一个 Key 会有不同的随机数前缀,在进行

reduceByKey 操作的时候原来的一个非常大的倾斜的 Key 就分而治之变成

若干个更小的 Key,不过此时结果和原来不一样,怎么破?进行 map 操

作,目的是把随机数前缀去掉,然后再次进行 reduceByKey 操作。(当

然,如果你很无聊,可以再次做随机数前缀),这样我们就可以把原本倾

斜的 Key 通过分而治之方案分散开来,最后又进行了全局聚合

注意 1: 如果此时依旧存在问题,建议筛选出倾斜的数据单独处

理。最后将这份数据与正常的数据进行 union 即可。

注意 2: 单独处理异常数据时,可以配合使用 Map Join 解决。

2、spark 使用不当造成的数据倾斜

提高 shuffle 并行度

dataFrame 和 sparkSql 可以设置 spark.sql.shuffle.partitions

参数控制 shuffle 的并发度,默认为 200。

rdd 操作可以设置 spark.default.parallelism 控制并发度,默认

参数由不同的 Cluster Manager 控制。

局限性: 只是让每个 task 执行更少的不同的 key。无法解决个别

key 特别大的情况造成的倾斜,如果某些 key 的大小非常大,即使一个

task 单独执行它,也会受到数据倾斜的困扰。

使用 map join 代替 reduce join

在小表不是特别大(取决于你的 executor 大小)的情况下使用,可

以使程序避免 shuffle 的过程,自然也就没有数据倾斜的困扰了.(详细见

http://blog.csdn.net/lsshlsw/article/details/50834858、

http://blog.csdn.net/lsshlsw/article/details/48694893)局限性: 因为是先将小数据发送到每个 executor 上,所以数据量

不能太大。

 

第二篇文章:

文章来源:http://www.sohu.com/a/105957961_164987

数据倾斜的原因:

在Shuffle阶段,同样的key的数据条数太多了,导致某个key所在的Task的数据量太大

了,远超过其他的Task处理的数据,所以其他Task需要等它结束才能collect。慢慢慢

搞定数据倾斜需要:

搞定shuffle

搞定业务场景

搞定cpu core的使用抢矿

搞定OOM的根本原因

所以搞定了数据倾斜需要对至少以上的原理了如指掌。所以搞定数据倾斜是关键中的关

键。

告诉大家一个屡试不爽的经验结论:一般情况下,OOM的原因都是数据倾斜。某个task

任务数据量太大,GC的压力就很大。这比不了Kafka,因为kafka的内存是不经过JVM的。是

基于Linux内核的Page.

数据倾斜发生的原理:

如何定位导致数据倾斜的代码

数据倾斜只会发生在shuffle过程中。这里给大家罗列一些常用的并且可能会触发shuffle

操作的算子:distinct、groupByKey、reduceByKey、aggregateByKey、join、

cogroup、repartition等。出现数据倾斜时,可能就是你的代码中使用了这些算子中的某

一个所导致的。

某个task执行特别慢的情况

解决方案一:Hive ETL

治标不治本,提前进行预处理,形成宽表,然后在spark查询

解决方案二:过滤少数导致倾斜的key

需要提前计算哪个是导致OOM的key,然后在spark-sql的时候过滤掉但适用场景不多

解决方案三:提高shuffle操作的并行度

必须要迎难而上的时候最简单的方法,但使用场景不多

reduceByKey(1000),给1000个task同时执行,spark.sql.shuffle.partitions,该参数

代表了shuffle read task的并行度,该值默认是200,对于很多场景来说都有点过小。

解决方案四:两阶段聚合(局部聚合+全局聚合)

方案适用场景:对RDD执行reduceByKey等聚合类shuffle算子或者在Spark SQL中使用

group by语句进行分组聚合时,比较适用这种方案。

然后给key加上随机数,比如(hello, 1) (hello, 1) (hello, 1) (hello, 1),就会变成

(1_hello, 1) (1_hello, 1) (2_hello, 1) (2_hello, 1)。接着对打上随机数后的数据,执行

reduceByKey等聚合操作,进行局部聚合,

但是作用范围比较局限

解决方案五:将reduce join转为map join (适合于一大一小两个表)

方案适用场景:在对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而

且join操作中的一个RDD或表的数据量比较小(比如几百M或者一两G),比较适用此方

案。

实现思路:将较小的RDD利用collect算子拉渠道Driver端的内存中来,然后对其创建一

个Broadcast变量,然后对另外一个RDD执行map类算子,在算子函数内,获取Broadcast

中较小的RDD的全量数据,和当前RDD的每一条数据按照连接key进行对比,key相同,就

将两个RDD的数据用需要的方式连接起来

适用场景不多,因为需要将小表广播,消耗大量内存资源。

解决方案六:采样倾斜key并分拆join操作

方案适用场景:两个RDD/Hive表进行join的时候,如果数据量都比较大,无法采用“解决

方案五”,那么此时可以看一下两个RDD/Hive表中的key分布情况。如果出现数据倾斜,

是因为其中某一个RDD/Hive表中的少数几个key的数据量过大,而另一个RDD/Hive表中

的所有key都分布比较均匀,那么采用这个解决方案是比较合适的。

方案实现思路:

1、对包含少数几个数据量过大的key的那个RDD,通过sample算子采样出一份样本来,然

后统计一下每个key的数量,计算出来数据量最大的是哪几个key。2、然后将这几个key对应的数据从原来的RDD中拆分出来,形成一个单独的RDD,并给每

个key都打上n以内的随机数作为前缀,而不会导致倾斜的大部分key形成另外一个RDD。

3、接着将需要join的另一个RDD,也过滤出来那几个倾斜key对应的数据并形成一个单独

的RDD,将每条数据膨胀成n条数据,这n条数据都按顺序附加一个0~n的前缀,不会导致

倾斜的大部分key也形成另外一个RDD。

4、再将附加了随机前缀的独立RDD与另一个膨胀n倍的独立RDD进行join,此时就可以将

原先相同的key打散成n份,分散到多个task中去进行join了。

5、而另外两个普通的RDD就照常join即可。

6、最后将两次join的结果使用union算子合并起来即可,就是最终的join结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值