【Spark优化】

当 Spark 涉及到数据库的操作时,如何减少 Spark 运行中的数据库连接数?

使用 foreachPartition 代替 foreach,在 foreachPartition 内获取数据库的连接。
优化数据库性能:
·foreach 算子是遍历 RDD 的每条数据,因此,每条数据都会建立一个数据库连接,这是对资源的极大浪费
foreachPartition 是将 RDD 的每个分区作为遍历对象,一个分区的数据只需要创建一次数据库连接
优化部分
·一次处理一整个分区的数据;
·一个分区内的数据,创建唯一的数据库连接
·只需要向数据库发送一次 SQL 语句和多组参数;

Spark性能调优

常规性能调优

·最优资源配置:为任务分配更多的资源,在一定范围内,增加资源的分配与性能的提升是成正比的,实现了最优的资源配置后,再考虑其他调优手段。
· Executor个数: --num-executors
·增加每个 Executor 的 CPU core 个数: --executor-cores
·增加每个 Executor 的内存量: --executor-memory
·RDD优化
·避免创建重复的RDD,尽可能复用同一个RDD
·对多次使用的RDD进行持久化
·并行度调节
·通过参数设置,Spark 官方推荐, task 数量应该设置为 Spark 作业总 CPU core 数量的 2~3 倍。
·参数设置对于Spark SQL 是不生效的,Sparksql可以在查询出来的RDD后,立即使用repartition算子,重新分为多个分区,之后的RDD操作不涉及Sparksql,所以并行度就会等于参数设置的值,这样就避免了 Spark SQL 所在的 stage 只能用少量的 task 去处理大量数据并执行复杂的算法逻辑。
·广播大变量
task 中的算子中如果使用了外部的变量,每个 task 都会获取一份变量的复本,这就造成了内存的极大消耗。
·使用Kryo 序列化优化
Kryo 序列化机制比 Java 序列化机制性能提高 10 倍左右。Kryo序列化不支持所有对象的序列化,并且Kryo 需要用户在使用前注册需要序列化的类型,不够方便。
·调节本地化等待时长
Spark分配资源给task时,会从本地化最高级开始,Spark会等待一段时间,默认 3s,如果等待后仍然无法在该等级获取资源,那么会自动降级,直到获取到资源。可以延长等待时长,看看性能有没有提升。

算子调优

·在数据量不是特别大情况下,mapPartitions替代map。
如果数据量非常大时使用 mapPartitions 算子,函数一次处理一个分区的数据,如果一旦内存不足,此时无法回收内存,就可能会 OOM,即内存溢出。
·foreachPartition 优化数据库操作,使用foreachPartitions替代foreach
·在filter之后进行coalesce操作
·使用reduceByKey/aggregateByKey替代groupByKey
Reducebykey相对于其他shuffle操作有个显著特点:进行 map 端的本地聚合

shuffle调优

·调节 map 端缓冲区大小
如果 shuffle 的 map 端处理的数据量比较大,但是 map 端缓冲的大小是固定的,可能会出现 map 端缓冲数据频繁 spill 溢写到磁盘文件中的情况,使得性能非常低下,通过调节 map 端缓冲的大小,可以避免频繁的磁盘 IO 操作
·调节 reduce 端拉取数据缓冲区大小
如果内存资源较为充足,适当增加拉取数据缓冲区的大小,可以减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。
·调节 reduce 端拉取数据重试次数
对于那些包含了特别耗时的 shuffle 操作的作业,建议增加重试最大次数(比如 60 次),以避免由于 JVM 的 full gc 或者网络不稳定等因素导致的数据拉取失败。
·调节 reduce 端拉取数据等待间隔
在拉取过程出现失败后,会等待一定的时间间隔再进行重试,可以通过加大间隔时长(比如 60s),以增加 shuffle 操作的稳定性。
·调节 SortShuffle 排序操作阈值
当使用sortshuffle时,不需要排序操作,就建议把排序阈值调大,不进行排序。

Filter过滤后会产生什么问题?如何解决?

会产生两个问题
·浪费过滤后分区中task的计算资源。如果分区还是原来设置与上游task数量相同,过滤之后每个分区的task数量减少,造成资源浪费。
·过滤后每个分区的数据量不一致,可能出现数据倾斜问题。
解决:
·过滤后数据量变小,分区数适当减少,避免资源浪费;
·对分区数据重新分配,让每个分区数量差不多,避免资源浪费。
实现在过滤之后:
·多数分区合并为少数分区:(减少分区)
如果减少不多,使用无shuffle的coalesce,
减少很多,则启动shuffle过程。
·少数分区分解为多数分区(增加分区)
使用 repartition。或coalesce 的shuffle 设置为 true。

如何解决数据倾斜问题?

主要指 shuffle 过程中出现的数据倾斜问题,是由于不同的 key对应的数据量不同导致的不同 task 所处理的数据量不同的问题。
数据倾斜原因有以下几方面:
·key 分布不均匀;建表时考虑不周,业务数据激增

数据倾斜的表现

➢ Spark 作业的大部分 task 都执行迅速,只有有限的几个 task 执行的非常慢,此时可能出现了数据倾斜,作业可以运行,但是运行得非常慢;
➢ Spark 作业的大部分 task 都执行迅速,但是有的 task 在运行过程中会突然报出 OOM,反复执行几次都在某一个 task 报出 OOM 错误,此时可能出现了数据倾斜,作业无法正
常运行。

定位数据倾斜问题

➢ 查阅代码中的 shuffle 算子,例如 reduceByKey、 countByKey、 groupByKey、 join 等算子,根据代码逻辑判断此处是否会出现数据倾斜;
➢ 查看 Spark 作业的 log 文件, log文件对于错误的记录会精确到代码的某一行,可以根据异常定位到的代码位置来明确错误发生在第几个 stage,对应的 shuffle 算子是哪一个;

解决方案

----聚合原数据
·避免shuffle过程。如果spark作业的数据来源于Hive,就在Hive表中对数据进行聚合。
·增大 key 粒度。这样key之间的差异性就会减少,减轻数据倾斜现象。此方法只针对特定类型的数据有效,当应用场景不适宜时,会加重数据倾斜。
----过滤导致倾斜的 key
如果在 Spark 作业中允许丢弃某些数据,那么可以考虑将可能导致数据倾斜的 key 进行过滤。
----提高 shuffle 操作中的 reduce 并行度
reduce 端并行度的提高就增加了 reduce 端 task 的数量,那么每个 task分配到的数据量就会相应减少,由此缓解数据倾斜问题。不一定有效,没有效果就尝试其他方案。
----使用随机 key 实现双重聚合(两阶段聚合:局部聚合+全局聚合)
首先,通过 map 算子给每个数据的 key 添加随机数前缀,对 key 进行打散,将原先一样的 key 变成不一样的 key,然后进行第一次聚合,这样就可以让原本被一个 task 处理的数据分散到多个 task 上去做局部聚合;
随后,去除掉每个 key 的前缀,再次进行聚合。
场景:此方法对于由 groupByKey、 reduceByKey 这类算子造成的数据倾斜由比较好的效果,仅仅适用于聚合类的 shuffle 操作,适用范围相对较窄。如果是 join 类的 shuffle 操作,还得用其他的解决方案。
----将 reduce join 转换为 map join
Reduce join是走shuffle过程,可以用map join代替,也就是采用广播小 RDD 全量数据+map 算子来实现,
具体过程:将较小 RDD 中的数据直接通过 collect 算子拉取到 Driver 端的内存中,然后对其创建一个 Broadcast 变量;接着对另外一个 RDD 执行 map 类算子,在算子函数内,从 Broadcast 变量中获取较小 RDD 的全量数据,与当前 RDD 的每一条数据按照连接 key 进行比对,如果连接 key 相同的话,那么就将两个 RDD 的数据用你需要的方式连接起来。
可以实现同样的效果,不进行shuffle操作,就不会发生数据倾斜。
场景:这个方法适合join 操作有数据倾斜问题并且其中一个 RDD 的数据量较小的场景。
----sample 采样对倾斜 key 单独进行 join
在 Spark 中,如果某个 RDD 只有一个 key,那么在 shuffle 过程中会默认将此 key 对应的数据打散,由不同的 reduce 端 task 进行处理。
根据这点,将发生数据倾斜的 key 单独提取出来,组成一个RDD,然后与其他 RDD 单独 join,此时倾斜的数据会被打散。
场景:适合倾斜时key数量较少的情况,当数据量非常大时,可以考虑使用 sample 采样获取 10%的数据,然后分析这 10%的数据中哪个 key 可能会导致数据倾斜,然后将这个 key 对应的数据单独提取出来。
----使用随机数扩容进行 join
选择一个 RDD,使用 flatMap 进行扩容,对每条数据的 key 添加数值前缀(1~N 的数值),将一条数据映射为多条数据;(扩容)
选择另外一个 RDD,进行 map 映射操作,每条数据的 key 都打上一个随机数作为前缀(1~N 的随机数);(稀释)
场景:如果在进行 join 操作时, RDD 中有大量的 key 导致数据倾斜,那么进行分拆 key 也没什么意义,此时就只能使用最后一种方案来解决问题了。
----多种方案组合使用
如果要处理一个较为复杂的数据倾斜场景,那么可能需要将多种方案组合起来使用。
·比如说,我们针对出现了多个数据倾斜环节的 Spark 作业,可以先运用解决方案一HiveETL 预处理和过滤少数导致倾斜的 k,预处理一部分数据,并过滤一部分数据来缓解;
·其次可以对某些 shuffle 操作提升并行度,优化其性能;
·最后还可以针对不同的聚合或 join 操作,选择一种方案来优化其性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值