spark数据倾斜优化

数据倾斜是大数据计算中一个最棘手的问题,一旦出现数据倾斜的情况,会十分的影响任务的性能。可能会影响整个任务的进度,甚至可能出现任务 OOM 异常退出。数据倾斜的调优,就是利用各种技术方案解决不同类型的数据倾斜问题,保证 Spark 作业的性能。

数据倾斜的概念:

mapreduce程序执行时,大部分节点执行任务完毕,但是有一个或者几个节点运行很慢,导致整个程序的处理时间很长,这可能是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完。最通俗易懂的话来说,数据倾斜无非就是大量的相同key被分配到一个分区里,造成了’一个人累死,其他人闲死’的情况。举一个极端的例子,当在执行一个shuffle操作时,根据key值的不同,分配到不同的reduce task进行处理,当多个不同的key值共有100万个的时候,假设某个key值有90万个,因此会被分到同一个reduce task进行处理,其他几个分别每个reduce task处理1万个,这个时候就会造成任务分配不均,假设处理一万个数据需要十分钟,那么其他几个reduce task 10分钟便可以完成,而这个时候处理90万个相同key值的reduce task则需要90分钟,足足比其他任务多了一个小时多一点,整体的性能会大大降低。

对于大数据分布式系统来说,理想情况下,随着节点数量的增加,应用整体耗时线性下降。下图展示了单机处理一个任务与分布式系统同时处理任务的时间比较,可以看出来,理想的情况下分布式处理的时间是单机处理时间的1/n(n表示节点的个数)。
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GTfv5ZGh-1651675837532)(C:\Users\Garth\AppData\Roaming\Typora\typora-user-images\image-20211226213450816.png)]

数据倾斜的表现形式

数据倾斜主要有两种表现形式:

1.通过监控界面发现大部分task,执行的都非常的快,可能不到一秒钟就运行出了结果,但是总是有最后几个task任务总是需要等好久才结束,严重拖延了整体执行的效率,这种很明显就是出现了数据倾斜,但是最终还会跑出结果。如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7fME5znj-1651675837534)(C:\Users\Garth\AppData\Roaming\Typora\typora-user-images\image-20211227052305713.png)]

2.还有一种就直接会跑不出结果。刚开始发现整体的task速度很快,但是突然发现任务失败,报错JVM Out Of Memory,task failed,task lost,resubmitting task,内存溢出等错误,多次再次尝试之后依旧不行,总在一个任务处报错,这个时候就是某个task处理的数据量太大,造成需要创建大量对象时候因内存不够而造成OOM。

数据倾斜的预防:

为了防止因数据倾斜造成效率低下,因此开始处理数据前对数据的规划是十分重要的,可以对数据源进行干预处理,防止数据分布不均。Spark 会通过 textFile(path, minPartitions) 方法读取文件,对于不可切分的文件,每个文件对应一个 Split 从而对应一个 Partition。此时各文件大小是否一致,很大程度上决定了是否存在数据源侧的数据倾斜。另外,对于不可切分的压缩文件,即使压缩后的文件大小一致,它所包含的实际数据量也可能差别很多,因为源文件数据重复度越高,压缩比越高。反过来,即使压缩文件大小接近,但由于压缩比可能差距很大,所需处理的数据量差距也可能很大。此时可通过在数据生成端将不可切分文件存储为可切分文件,或者保证各文件包含数据量相同的方式避免数据倾斜。比如在产生日志文件时候,每一个小时生成一个日志文件可能在不同的时间段产生的文件大小不同,这个时候可以通过调整参数,让每个日志根据大小的不同来产生而不是根据时间来产生。

数据倾斜的定位:

1.根据自己的程序来定位。导致数据倾斜的问题就是 shuffle 算子,因此我们可以查看代码中的对应的算子看哪个使用的不太合适,比如distinct、groupByKey、reduceByKey、aggergateByKey、join、cogroup、repartition 等。

2.根据日志来定位。log一般会报是在你的哪一行代码,导致了OOM异常。或者查看哪一个stage,task特别慢,通过页面的spark中stage的划分来定位,就能够通过stage定位到代码问题,发现哪里发生了数据倾斜。

数据倾斜的解决方案:

1.使用hive sql对数据源进行预先处理:

多数的情况下,数据来源都是hive表,当我们发现某个key值有了倾斜之后,可以根据hive的ETL任务来预先对数据按照 key 进行聚合,然后在 Spark 作业中针对的数据源就不是原来的 Hive 表了,而是预处理后的Hive表,此时由于数据已经预先进行过聚合或join操作了,那么在 Spark 作业中也就不需要使用原先的 shuffle 类算子执行这类操作了。但是这种方式属于治标不治本。因为毕竟数据本身就存在分布不均匀的问题,所以Hive ETL中进行group by或者join等shuffle操作时,还是会出现数据倾斜,导致Hive ETL的速度很慢。

2.提高shuffle操作reduce并行度

提高shuffle操作的reduce并行度将增加reduce task的数量,就可以让每个reduce task分配到更少的数据量,这样的话,也许就可以缓解,或者甚至是基本解决掉数据倾斜的问题,防止了OOM的产生。但是这种办法也是治标不治本,因为它没有从根本上改变数据倾斜的本质和问题。只是尽可能地去缓解和减轻shuffle reduce task的数据压力,以及数据倾斜的问题。

3.使用随机数以及扩容表进行join

这个方案没有彻底解决数据倾斜的,仅仅是一种对数据倾斜的缓解。具体的步骤如下:

1、选择一个RDD,要用flatMap,进行扩容(比较小的RDD),将每条数据,映射为多条数据,每个映射出来的数据,都带了一个n以内的随机数,通常来说,会选择10以内。

2、将另外一个RDD,做普通的map映射操作,每条数据,都打上一个10以内的随机数。

3、最后,将两个处理后的RDD,进行join操作。

4.过滤少数导致倾斜的key

如果发现导致倾斜的 key 就少数几个,而且对计算本身的影响并不大的话,那么很适合使用这种方案。比如 99% 的 key 就对应 10 条数据,但是只有一个 key 对应了 100 万数据,从而导致了数据倾斜。如果我们判断那少数几个数据量特别多的 key,对作业的执行和计算结果不是特别重要的话,那么干脆就直接过滤掉那少数几个 key。比如,在 Spark SQL 中可以使用 where 子句过滤掉这些 key 或者在SparkCore 中对 RDD 执行 filter 算子过滤掉这些 key。如果需要每次作业执行时,动态判定哪些 key的数据量最多然后再进行过滤,那么可以使用 sample 算子对 RDD 进行采样,然后计算出每个 key 的数量,取数据量最多的 key 过滤掉即可。主要是将导致数据倾斜的 key 给过滤掉之后,这些 key 就不会参与计算了,自然不可能产生数据倾斜。

5.采样倾斜key进行两次join

这种方法是对第四种方法的改进,当少数几个导致倾斜的 key还是必须要的时候,可以使用本方法。本方法关键之处在于,将发生数据倾斜的key,单独拉出来,放到一个RDD中去;就用这个原本会倾斜的key RDD跟其他RDD,单独去join一下,这个时候,key对应的数据,可能就会分散到多个task中去进行join操作,最后将join后的表进行union操作。就不至于,这个key跟之前其他的key混合在一个RDD中时,导致一个key对应的所有数据,都到一个task中去,就会导致数据倾斜。

6.将reduce join转为map join

不使用join算子进行连接操作,而使用Broadcast变量与map类算子实现join操作,进而完全规避掉shuffle类的操作,彻底避免数据倾斜的发生和出现。将较小RDD中的数据直接通过collect算子拉取到Driver端的内存中来,然后对其创建一个Broadcast变量;接着对另外一个RDD执行map类算子,在算子函数内,从Broadcast变量中获取较小RDD的全量数据,与当前RDD的每一条数据按照连接key进行比对,如果连接key相同的话,那么就将两个RDD的数据用你需要的方式连接起来。

7.分两个阶段聚合

这个方案的核心实现思路就是进行两阶段聚合。第一次是局部聚合,先给每个key都打上一个随机数,比如10以内的随机数,此时原先一样的key就变成不一样的了,比如(hello, 1) (hello, 1) (hello, 1) (hello,1),就会变成(1_hello, 1) (1_hello, 1) (2_hello, 1) (2_hello, 1)。接着对打上随机数后的数据,执行reduceByKey等聚合操作,进行局部聚合,那么局部聚合结果,就会变成了(1_hello, 2) (2_hello, 2)。然后将各个key的前缀给去掉,就会变成(hello,2)(hello,2),再次进行全局聚合操作,就可以得到最终结果了,比如(hello, 4)。
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值