spark性能优化:数据倾斜调优

直接上整理的干货

什么是数据倾斜?

数据倾斜的原理很简单:在进行shuffle的时候,需要将各个节点上的相同key的数据拉取到某个节点上的一个task中进行处理,比如按照key进行聚合或者join等操作。此时如果某个key数据量特别大的话就会导致数据倾斜。比如有些key只有10条数据运行1s,但是有的则有100万条运行好几个小时甚至OOM。

如何定义数据倾斜代码?

首先上面说过,数据倾斜是发生在shuffle中,因此首先我们要先了解哪些算子会导致数据倾斜reducebykey/aggreatebykey/join/repartition/groupbykey/join/cogroup等具体参考:https://blog.csdn.net/yrsg666/article/details/92837145。yarn-client模式在界面可以直接看到处在哪个阶段;如果是yarn-cluter可以在spark-web-UI上看到这个stage各个task的分布情况看到其运行时间等然后根据stage的划分原理反推回是哪个算子导致数据倾斜。以wordcount为例,在reducebykey两侧划分为两个stage阶段stage0阶段主要是从textfile到map以及执行shuffle的write操作,注意是每个分区会将自己分区内相同key的值写入一个文件中。然后stage1执行reducebykey到collect的操作,首先就是shuffle read操作,这个时候会从各个分区拉取这个key到某一个分区中,进行聚合操作。

如何解决数据倾斜?

方案一:使用ETL预处理数据

适用场景:导致数据倾斜的是hive表,如果该hive表中的数据本身很不均匀(某个key对应100万,其他才10条数据),而业务场景中需要频繁使用spark对hive表执行某个分析操作

实现思路:可以评估,是否可以通过hive来进行数据的预处理也就是hive ETL预先对数据进行聚合,或者是预先跟其他表进行join等操作。这个时候等spark拿到数据的时候已经是在hive中ETL之后的结果数据了这个时候就会数据量减小。

优缺点:此种方案在hive上进行了预处理操作减少了spark当中的数据操作量。但是由于数据量本身分布就是不均匀,治标不治本,导致在hive中进行key聚合或者join等ETL操作时还是执行慢,相当于转移了倾斜位置。

实践:在一些java与saprk结合的场景中,会出现一些java频繁调用spark的场景,对saprk的时序要求比较高,这个时候将数据倾斜的时间提前到上游的hive ETL,每天只执行一次,后续就会让spark的运行效率提高很多。

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

适用场景:某些导致数据倾斜的数据对计算结果并不是特别重要。这个时候就可以考虑将倾斜key过滤掉。

实现思路:比如在saprkSQL中可以使用where子句而在spark RDD中可以使用filter进行过滤。如果需要每次作业时候,动态判断哪些key的数据量最多然后再进行过滤,可以使用sample算子对RDD进行采样。

优缺点:此种方案效果肯定很好,实现也简单,但是使用场景并不多。大多数导致数据倾斜的key还是很多的。

实践:某天发现spark计算的时候OOM了,这个时候发现是数据异常,这个时候就是采样然后直接过滤掉计算。

方案三:提高shuffle的并行度

适用场景:如果shuffle无法避免,必须要迎难而上,那就采用此种方案,提高并行度。这种方法是处理最简单的方法了。

实现思路:在对RDD进行shuffle的时候给shuffle出入一个参数比如reducebykey(1000),这个参数就是指定了shuffle read task时候的数量;也可以设置一个default值new SparkConf().set(“spark.defalut.parallelism”,”500”);如果读取的数据在HDFS上,增加block数,默认情况下split与block是一对一的,而split又与RDD中的partition对应,所以增加了block数,也就提高了并行度;RDD.repartition,给RDD重新设置partition的数量 [repartitions 或者 coalesce];而在sparksql通过spark.sql.shuffle.partitions(默认200) ,来提高并行度。官方推荐,task数量,设置成spark Application 总cpu core数量的2~3倍 ,比如150个cpu core ,基本设置 task数量为 300~ 500

实现原理:通过增加shuffle read task 来增加任务数来缩短task的执行时间。

优缺点:未解决数据倾斜但是有效缓解了数据倾斜的影响。

方案四:两阶段聚合

适用场景:对RDD执行reducebykey等聚合类shuffle算子或者在sparksql中使用groupbykey语句进行分组聚合时,也比较适合

实现思路:核心就是分作两阶段聚合。先局部聚合然后再全局聚合,这样所谓的局部聚合,就拿workcount来说。将多个(hello,1)增加随机数改写成(1_hello,1),(2_hello,1)然后对这种带前缀的线reducebykey然后再将前缀去掉,再进行reducebykey。

优缺点:对于聚合类shuffle数据倾斜会有很好的提升效果。但是也仅仅只能用于聚合类操作,使用范围较窄,如果是join类操作还得其他方案。将pairRDD用maptopari算子打随机前缀,然后聚合,然后再用maptopari去掉随机前缀然后再聚合,具体代码见下方参考链接

方案五:将reduce join转换为map join

适用场景:在对RDD适用join类操作,或者sparksql中使用join的时候,其中一个RDD或者表的数据量比较少。

实现思路:直接替换掉join算子,而是使用broadcast和map类算子实现join操作,规避掉shuffle,避免数据倾斜。首先通过collect将较小RDD拉取到driver内存中,将其创建为一个broadcast变量,接着对另外一个RDD执行map类算子,在算子函数内部从broadcast变量中获取较小RDD的全量数据,与当前RDD的每一条数据按照连接key进行比对,如果连接key相同的话,那么就将两个RDD的数据用你需要的方式连接起来。

实现原理:普通的join操作是会走shuffle流程,一旦shuffle就相当于将相同key的数据拉取到一个shuffle read task中再进行join,此时就是reduce join,但是如果一个RDD是较小的,则可以采用广播小RDD全量数据+map算子来实现与join相同的效果,也就是map join,此时就不会发生shuffle操作,也不会数据倾斜。

优缺点:对join操作导致的数据倾斜,效果很好,直接规避了join操作。但是适用场景较少,仅适合一个大表与一个小表进行join操作的时候。毕竟对一个RDD进行广播driver以及每个executor中都会驻留一份小RDD的全量数据,如果广播出去的比较大,比如10G以上,那么可能直接就OOM了。具体操作详见下方参考链接

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

适用场景:两个RDD/hive表都很大的时候,无法采用方案五,那么此时可以看下一下两个RDD/hive表,是否是某个RDD或者hive表中的某几个key比较大,而另一个比较均匀,如果是这种情况那么采用此种方案比较合适。

实现思路:1、首先对数据倾斜的哪个RDD/hive表使用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进行了单独处理分散到多个task中去处理了。5、将另外两个各自剩余的的哪两个rdd进行join。6、最后是将两次join的结果union算子合并一下即可。

实现原理:对于导致join数据倾斜的key进行拆分单独处理,将这部分key单独取出来拿到多个task中执行。避免了多个key的大内存占用。

优缺点:对于join导致的数据倾斜,如果只是某几个key那采用此种方式非常有效的可以打散数据。但是如果导致数据倾斜的key特别多的话此种方式就不合适了,毕竟内存没那么大……

方案七:使用随机前缀和扩容RDD进行join

适用场景:如果进行join的时候有大量的key导致数据倾斜,那么拆分key没有意义,只能用最后一种方案。

实现思路:1、该方案和方案六基本类似,首先通过sample采样或者hive表查看找到数据倾斜的RDD与hive表,比如有多个key都对应了超过1万条数据。2、将该RDD内的每条key都打上n以内的随机数。3、对另外一个RDD进行扩容成n条数据然后在进行join操作,这样的话保证每条数据都不会丢失能够join到。4、join即可

实现原理:使用随机数打散其中一张表的过多的rowkey,让不同的task去处理不同的key。

优缺点:此种方案,个人感觉还是适用于一张大表/rdd,一张小表/rdd 尤其是另外一个扩容的也要注意大小。对内存要求很高。

方案八:多种方案组合

在数据倾斜当中,一般倾斜原因比较简单的话适用上面一种方案就可以,但是实际当中场景比较复杂,因此有时候也需要多种场景进行组合处理。比如说,我们针对多个不同数据倾斜的环节,可以先适用方案一二,预处理一部分倾斜数据,过滤掉一部分数据来缓解,其次可以采用方案三对某些shuffle提高并行度,这样实现简单,或者如果是key操作的话还可以用方案四进行分步骤聚合操作先局部在全局如果是join操作呢,可以先考虑方案五适用broadcast直接规避聚合操作。再其次使用方案六、七对数据进行采样查看是否需要拆分key或者是直接全部随机然后扩容join。

本文转载自:https://www.iteblog.com/archives/1671.html

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值