Spark数据倾斜及解决方案

一,数据倾斜现象及原理
发生数据倾斜以后的现象:
1、你的大部分的task,都执行的特别特别快,刷刷刷,就执行完了(你要用client模式,standalone client,yarn client,本地机器只要一执行spark-submit脚本,就会开始打印log),task175 finished;剩下几个task,执行的特别特别慢,前面的task,一般1s可以执行完5个;最后发现1000个task,998,999 task,要执行1个小时,2个小时才能执行完一个task。
出现数据倾斜了
还算好的,因为虽然老牛拉破车一样,非常慢,但是至少还能跑。
2、运行的时候,其他task都刷刷刷执行完了,也没什么特别的问题;但是有的task,就是会突然间,啪,报了一个OOM,JVM Out Of Memory,内存溢出了,task failed,task lost,resubmitting task。反复执行几次都到了某个task就是跑不通,最后就挂掉。
某个task就直接OOM,那么基本上也是因为数据倾斜了,task分配的数量实在是太大了!!!所以内存放不下,然后你的task每处理一条数据,还要创建大量的对象。内存爆掉了。
出现数据倾斜了
数据倾斜的原理:
在这里插入图片描述

定位出现问题的位置:
根据log去定位
出现数据倾斜的原因,基本只可能是因为发生了shuffle操作,在shuffle的过程中,出现了数据倾斜的问题。因为某个,或者某些key对应的数据,远远的高于其他的key。
1、你在自己的程序里面找找,哪些地方用了会产生shuffle的算子,groupByKey、countByKey、reduceByKey、join
2、看log
log一般会报你的哪一行代码,导致了OOM异常;或者呢,看log,看看是执行到了第几个stage!!!
哪一个stage,task特别慢,就能够自己用肉眼去对你的spark代码进行stage的划分,就能够通过stage定位到你的代码,哪里发生了数据倾斜
去找找,代码那个地方,是哪个shuffle操作。
二,聚合源数据以及过滤导致倾斜的key
聚合源数据第一个方案:
spark作业的源表,hive表,其实通常情况下来说,也是通过某些hive etl生成的。hive etl可能是晚上凌晨在那儿跑。
直接在生成hive表的hive etl中,对数据进行聚合。比如按key来分组,将key对应的所有的values,全部用一种特殊的格式,拼接到一个字符串里面去,比如“key=sessionid, value: action_seq=1|user_id=1|search_keyword=火锅|category_id=001;action_seq=2|user_id=1|search_keyword=涮肉|category_id=001”。

这样每个key就只对应一条数据。在spark中,拿到key=sessionid,values,就不需要再去执行groupByKey+map这种操作了。直接对每个key对应的values字符串,map操作,进行你需要的操作即可。就不需要执行shffule操作了,也就不可能导致数据倾斜
聚合源数据方第二个方案:
你可能没有办法对每个key,就聚合出来一条数据;
那么也可以做一个妥协;对每个key对应的数据,10万条;有好几个粒度,比如10万条里面包含了几个城市、几天、几个地区的数据,现在放粗粒度;直接就按照城市粒度(group by city_id),做一下聚合,几个城市,几天、几个地区粒度的数据,都给聚合起来。比如说
city_id date area_id
select … from … group by city_id
尽量去聚合,减少每个key对应的数量,也许聚合到比较粗的粒度之后,原先有10万数据量的key,现在只有1万数据量。减轻数据倾斜的现象和问题。

过滤导致倾斜的key
如果你能够接受某些数据,在spark作业中直接就摒弃掉,不使用。比如说,总共有100万个key。只有2个key,是数据量达到10万的。其他所有的key,对应的数量都是几十。
这个时候,你自己可以去取舍,如果业务和需求可以理解和接受的话,在你从hive表查询源数据的时候,直接在sql中用where条件,过滤掉某几个key。
那么这几个原先有大量数据,会导致数据倾斜的key,被过滤掉之后,那么在你的spark作业中,就不会发生数据倾斜了。

三,提高shuffle操作reduce并行度
将reduce task的数量,变多,就可以让每个reduce task分配到更少的数据量,这样的话,也许就可以缓解,或者甚至是基本解决掉数据倾斜
给我们所有的shuffle算子,比如groupByKey、countByKey、reduceByKey。在调用的时候,传入进去一个参数。那个数字,代表了那个shuffle操作的reduce端的并行度。那么在进行shuffle操作的时候,就会对应着创建指定数量的reduce task。默认是200
比如说,原本某个task分配数据特别多,直接OOM,内存溢出了,程序没法运行,直接挂掉。按照log,找到发生数据倾斜的shuffle操作,给它传入一个并行度数字,这样的话,原先那个task分配到的数据,肯定会变少。就至少可以避免OOM的情况,程序至少是可以跑的。

实际生产环境中的经验。
1、如果最理想的情况下,提升并行度以后,减轻了数据倾斜的问题,或者甚至可以让数据倾斜的现象忽略不计,那么就最好。就不用做其他的数据倾斜解决方案了。
2、不太理想的情况下,就是比如之前某个task运行特别慢,要5个小时,现在稍微快了一点,变成了4个小时;或者是原先运行到某个task,直接OOM,现在至少不会OOM了,但是那个task运行特别慢,要5个小时才能跑完。
如果出现第二种情况,就立即放弃方案,开始尝试别的方案
四,使用随机key实现双重聚合
使用随机key实现双重聚合原理
Spark数据倾斜及解决方案_第1张图片
使用场景
(1)groupByKey
(2)reduceByKey
第一轮聚合的时候,对key进行打散,将原先一样的key,变成不一样的key,相当于是将每个key分为多组;
先针对多个组,进行key的局部聚合;接着,再去除掉每个key的前缀,然后对所有的key,进行全局的聚合。
对groupByKey、reduceByKey造成的数据倾斜,有比较好的效果。
五,将reduce join转换为map join
普通的join,肯定走shuffle;肯定走的是reduce join。先将所有相同的key,对应的values,汇聚到一个task中,然后再进行join。
Spark数据倾斜及解决方案_第2张图片
reduce join转换为map join,适合在什么样的情况下,可以来使用?
其中一个RDD必须是比较小的,broadcast出去那个小RDD的数据以后,就会在每个executor的block manager中都驻留一份。要确保你的内存足够存放那个小RDD中的数据
这种方式下,根本不会发生shuffle操作,肯定也不会发生数据倾斜。两个RDD都比较大,那么这个时候,你去将其中一个RDD做成broadcast,就很笨拙了。很可能导致内存不足。最终导致内存溢出,程序挂掉。
Spark数据倾斜及解决方案_第3张图片
六,sample采样倾斜key单独进行join
将发生数据倾斜的key,单独拉出来,放到一个RDD中去;用这个原本会倾斜的key RDD跟其他RDD,单独去join一下,这个时候,key对应的数据,可能就会分散到多个task中去进行join操作。就不至于这个key跟之前其他的key混合在一个RDD中时,导致一个key对应的所有数据,都到一个task中去,就会导致数据倾斜。

Spark数据倾斜及解决方案_第4张图片
这种方案什么时候适合使用?
尽量建议,比如就是一个key对应的数据量特别多。
此时可以采用咱们的这种方案,单拉出来那个最多的key;单独进行join,尽可能地将key分散到各个task上去进行join操作。
什么时候不适用呢?
如果一个RDD中,导致数据倾斜的key,特别多;那么此时,最好还是不要这样了;还是使用我们最后一个方案,终极的join数据倾斜的解决方案。
Spark数据倾斜及解决方案_第5张图片
七,使用随机数以及扩容表进行join
八,其它
Spark数据倾斜及解决方案_第6张图片

你可能感兴趣的:(Spark数据倾斜及解决方案)