spark数据倾斜怎么解决?

1、在项目中有遇到过数据倾斜吗?

首先要知道什么是数据倾斜。我们知道,在执行shuffle操作的时候,相同的key对应的value一定会被分配到同一个reducetask中去处理,所以当一批数据中相同key的数据过多,就会导致一个reducetask迟迟跑不完。现在我们来定义一下数据倾斜的概念:一批数据中相同key的数据过多而导致其他reducetask跑完,而一个reducetask迟迟跑不完,甚至触发OOM的现象,称为数据倾斜。

在面试的时候,就算没有遇到过这个问题,我们也要回答遇到过,因为数据倾斜是大数据中非常常见的问题,如果你回答没有遇到过,那面试官可能会觉得你经验不够丰富,另一方面,很明显面试官想考考你这方面的知识,你回答没有,那不就把话题聊死了!那还这么面?所以我们必须要回答遇到过,然后用下面的知识在面试官面前装逼。

2、你在项目中的如何解决这个问题的?

2.1 定位发生数据倾斜的位置

如果发生数据倾斜,99.9%的可能性是因为shuffle操作将大量相同key的数据分配到同一个reducetask中去处理了(剩下0.1%看天)。所以我们首先要定位发生数据倾斜的位置。刚刚说了,发生数据倾斜是因为产生了shuffle操作,所以第一步就是找产生shuffle的RDD,要定位数据倾斜的位置,当然是去查log了,或者打开UI界面,看看是哪一个stage产生很慢,这个stage前面的ShuffledRDD,就是产生数据倾斜的罪魁祸首了。

2.2 对症下药

虽然产生数据倾斜的原因大致是一样的,但是也有些差别,同样处理方式也有些差别,下面我将逐个介绍在哪些地方可以处理数据倾斜。

2.2.1 源数据发生数据倾斜

Spark作业的来源通常是经过Hive ETL后放在HDFS中的数据,这里就可能会造成数据倾斜的问题,比如一个key对应10w条数据,而另一个key对应了100w条数据,那你跑spark任务的时候,肯定就会产生数据倾斜了。

解决办法

(1) ETL端做聚合
首先,针对这种情况,我们一般可以通过Hive ETL预先对数据按照key进行聚合,或者是预先和其他表进行join,然后在Spark作业中针对的数据源就不是原来的Hive表了,而是预处理后的Hive表。此时由于数据已经预先进行过聚合或join操作了,那么在Spark作业中也就不需要使用原先的shuffle类算子执行这类操作了。

但是,Hive ETL中进行group by或者join等shuffle操作时,还是会出现数据倾斜,导致Hive ETL的速度很慢。我们只是把数据倾斜的发生提前到了Hive ETL中。

(2) 对key做粒度细化
其次,我们可以选择对key做粒度细化,比如key原先是城市-人口,每一个key都对应着1000w人,现在我们将key进行粒度细化,使它变成县城-人口,这样每个key就对应着100w人,这也是一个解决办法。

(3)过滤导致数据倾斜的key
直接过滤掉那些引起倾斜的Key。这种方法很简单,既然你倾斜,那我不用你就完事。比如说,总共有100万个key。只有2个key,是数据量达到10 万的。其他所有的key,对应的数量都是几十,这样join后会引起倾斜。这个时候,自己可以去取舍,如果业务和需求可以理解和接受的话,在从hive 表查询源数据的时候,直接在sql中用where条件,过滤掉某几个key 。那么这几个原先有大量数据,会导致数据倾斜的key,被过滤掉之后,那么在的spark作业中,自然就不会发生数据倾斜了。

2.2.2 shuffle过程发生数据倾斜

如果是因为使用了shuffledRDD(如groupBykey、reduceBykey)导致了数据倾斜则可以使用下面的解决办法。

解决办法

(1)简单粗暴但有效—提高shuffle的操作并行度
在对RDD执行shuffle算子时,给shuffle算子传入一个参数,比如reduceByKey(1000),该参数就设置了这个shuffle算子执行时shuffle read task的数量。对于Spark SQL中的shuffle类语句,比如group by、join等。

需要设置一个参数,即spark.sql.shuffle.partitions,该参数代表了shuffle read task的并行度,该值默认是200,对于很多场景来说都有点过小。

其原理很简单,增加shuffle read task的数量,可以让原本分配给一个 task 的多个 key 分配给多个 task , 从而让每个 task 处理比原来更少的数据 。举例来说, 如果原本有5个key,每个key对应10条数据,这5个key都是分配给一个task的,那么这个task就要处理50条数据。而增加了shuffle read task以后, 每个task就分配到一个key,即每个task就处理10条数据,那么自然每个task的执行时间都会变短了。

但是,这种方法治标不治本,如果可以解决数据倾斜的问题,我们可以考虑使用这种方法。

(2) 对key进行加盐操作
所谓加盐,就是对key的前缀加随机值的操作,第一轮聚合的时候,对key进行打散,将原先一样的key,变成不一样的key,相当于是将每个key分为多组。先针对多个组,进行key的局部聚合。接着,再去除掉每个key的前缀,然后对所有的key进行全局的聚合。

2.2.3 大小表join 发生数据倾斜

当两个RDD要执行join操作的时候,它们肯定是要进行shuffle的,但是如果一个RDD数据量很大,而另一个RDD数据量很小,那么这样也会产生数据倾斜的问题。

解决办法

通常针对这种情况,我们的解决办法就是让join发生在map端(和mapreduce一样),直接让小的RDD变成一个广播变量,让每个excutor都保存一份进行join。这样就避免了shuffle操作。

值得注意的是,对于join这种操作,不光是考虑数据倾斜的问题。即使是没有数据倾斜问题,也完全可以优先考虑,用我们讲的这种高级的reduce join转map join的技术,不要用普通的join,去通过shuffle,进行数据的join。完全可以通过简单的map,使用map join的方式,牺牲一点内存资源。在可行的情况下,优先这么使用。

但是针对两个RDD都很大的情况下,这种情况就不适用了,很可能会造成OOM。

2.2.4 某一个key对应大量数据

之前说过,某一个key对应大量数据时,我们可以根据需要,直接在ETL时就使用where子句将导致数据倾斜的key过滤掉,但有时候我们不得不处理它,这就产生了一个问题:该怎么处理这个key呢?

解决办法

单拉出来那个最多的key,单独进行join,尽可能地将key分散到各个task上去进行join操作。

3、总结

这里要说明一下,上述解决方案是按适用性来进行列举的,也就是说,第一个,在数据源端进行聚合是最常用的解决方案,如果是一个方案不适用,才会使用下一个方案,其次,我们在面试过程中,要有条理地阐述各个解决方案,你可以说其中一种场景,使用了什么样的办法,解决了这个问题,不能一上来就把底全给交了,那面试官会觉得你在被答案,还是要假装思索一波的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值