【Spark】Day06-Spark高级课程:性能调优、算子调优、Shuffle调优、JVM调优、数据倾斜、TroubleShooting


一、Spark性能调优

1、常规性能调优

最优资源配置:Executor数量、Executor内存大小、CPU核心数量 & Driver内存

RDD优化:RDD复用、RDD持久化(序列化、副本机制)

并行度调节:各个 stage 的 task 的数量,应该设置为Spark 作业总 CPU core 数量的 2~3 倍

广播大变量:在每个 Executor 保存一个副本,此 Executor 的所有 task 共用此广播变 量,这让变量产生的副本数量大大减少

Kryo序列化:比java的序列化性能高,

调节本地化等待时长:val conf = new SparkConf() .set("spark.locality.wait", "6")

2、算子调优

mapPartitions:针对一个分区的数据,只需要建立一个数据库连接

foreachPartition 优化数据库操作:一次处理一整个分区的数据;但可能OOM

filter 与 coalesce 的配合使用:filter 操作之后,使用 coalesce 算子针对每个 partition 的数据量各不 相同的情况,压缩 partition 的数量,而且让每个 partition 的数据量尽量均匀紧凑,

repartition 解决 SparkSQL 低并行度问题:使用 repartition 算子,去重新进行分区,避免了 Spark SQL 所在 的 stage 只能用少量的 task 去处理大量数据并执行复杂的算法逻辑

reduceByKey 本地聚合:有 map 端 聚 合 的 特 性 , 使 得 网 络 传 输 的 数 据 量 减 小

3、Shuffle 调优

调节 map 端缓冲区大小:避免频繁的磁盘 IO 操作

调节 reduce 端拉取数据缓冲区大小:增加拉取数据缓冲区的大小,可以减少拉取数据的次数

调节 reduce 端拉取数据重试次数:避免由于 JVM 的 full gc 或者网络不稳定 等因素导致的数据拉取失败

调节 reduce 端拉取数据等待间隔通过加大 间隔时长(比如 60s),以增加 shuffle 操作的稳定性。

调节 SortShuffle 排序操作阈值:参数调大一些,大于 shuffle read task 的数量,那么此时 map-side 就不会进行排序,减少性能开销

4、JVM调优

降低 cache 操作的内存占比:可以通过 spark.storage.memoryFraction 参数进行指定

调节 Executor 堆外内存:会避免掉某些 JVM OOM 的异常问题,同时,可以提升 整体 Spark 作业的性能。

调节连接等待时长:GC时,Spark 的 Executor 进程就会停止工作,无法提供相应,此时,由 于没有响应,无法建立网络连接,会导致网络连接超时,避免部分的 XX 文件拉取失败、XX 文件 lost 等报错

二、Spark数据倾斜

不 同的 key 对应的数据量不同导致的不同 task 所处理的数据量不同

表现及定位

1、解决方案一:聚合原数据-避免shuffle、增大key的粒度

2、解决方案二:过滤导致倾斜的 key

3、解决方案三:提高 shuffle 操作中的 reduce 并行度(分散多个key):让原本分配给一个 task 的多个 key 分配给多 个 task,从而让每个 task 处理比原来更少的数据

4、解决方案四:使用随机 key 实现双重聚合:加前缀第一次聚合后,去掉前缀在进行局部聚合

5、解决方案五:将 reduce join 转换为 map join,采用广播小 RDD 全量数据+map 算子来实现

6、解决方案六:sample 采样对倾斜 key 单独 join到一个单独的RDD,shuffle时会被分散到多个task

7、解决方案七:使用随机数以及扩容进行 join,将原先一样的 key 通过附加随机前缀变成不一样的 key,然后就可以将 这些处理后的“不同 key”分散到多个 task 中去处理

三、Spark TroubleShooting

1、故障排除一:控制 reduce 端缓冲大小以避免 OOM

2、故障排除二:JVM GC 导致的 shuffle 文件拉取失败,增加重试次数和等待时间

3、故障排除三:解决各种序列化导致的报错:自定义类等必须可以序列化

4、故障排除四:解决算子函数返回 NULL 导致的问题:返回特殊值、filter、filter后继续调用coalesce 算子进行优化

5、故障排除五:解决 YARN-CLIENT 模式导致的网卡流量 激增问题:YARN-client (测试环境)模式下,Driver 启动在本地机器上,而 Driver 负责所有的任务 调度,需要与 YARN 集群上的多个 Executor 进行频繁的通信,生产环境下的YARN-cluster 模式不会产生

6、故障排除六:解决 YARN-CLUSTER 模式的 JVM 栈内存溢出无法执行问题:增加 PermGen 的容量,参数设置

7、故障排除七:解决 SparkSQL 导致的 JVM 栈内存溢出:将一条 sql 语句拆分为多条 sql 语句来执行

8、故障排除八:持久化与 checkpoint 的使用:对这个 RDD 进行 checkpoint,持久化到HDFS上