Spark调优相关

1、性能优化

1.1、出库任务

(1)出库任务:建议使用spark.default.parallelism参数设置partition的个数,repartition要消耗代价

(2)出库任务:是IO密集型而不是计算密集型,4cores * 2executors效果可能不如1core * 8excutors

1.2、持久化数据
  • 对于需要可持久化数据调用cache
出库ES之前需要确认rdd.count,避免空数据,count之前就需要cache一下,
因为后续还会用到,不cache的话count之前的步骤就会重复执行

2、参数优化

set spark.executor.memory=8g     //调内存
set spark.network.timeout=1200;     //调braodcast join超时时间,大表join小表时使用
set spark.sql.broadcastTimeout=1200;   //调braodcast join超时时间,大表join小表时使用
set spark.sql.autoBroadcastJoinThreshold=10485760;   //调braodcast join超时时间,大表join小表时使用,10M

set spark.hadoop.fs.hdfs.impl.disable.cache=false; //小文件过多时spark读取慢
set spark.speculation=true; //是否开启推测
set spark.speculation.quantile=0.1; //任务运行至10%时开始推测
set spark.speculation.multiplier=1; //慢于平均运行时间的1.0倍时启动推测
set spark.dynamicAllocation.minExecutors = 5; //动态分配回收时,最少保留executor数
set spark.sql.grouping.union.enabled = true; //优化rollup造成的mappartition 计算倾斜
set spark.locality.wait.process=0S //缩短计算时的数据本地化等待时间,默认3秒
set spark.locality.wait.node=0S //提高executor利用率
set spark.locality.wait.rack=0S //机架感知等待时间
set spark.yarn.max.executor.failures =50; //增加失败容忍度
mr开启推测:
set mapreduce.reduce.speculative=true
如果任务不想spark失败后转mr,可以加这个参数:
set hive.spark.failed.retry=false;
2.1、资源优化

(1)num-executors

  • 设置Spark作业总共要用多少个Executor进程来执行
  • Driver在向YARN集群管理器申请资源时,YARN集群管理器会尽可能按照你的设置来在集群的各个工作节点上,启动相应数量的Executor进程
* 过多的num-executors会增加申请等待时间和风险
* 申请过多的内存,影响集群其他业务
* 会增加executors之间传输的IO成本

(2)executor-cores

  • 该参数用于设置每个Executor进程的CPU core数量,决定了每个Executor进程并行执行task线程的能力。
  • 每个CPU core同一时间只能执行一个task线程,因此每个Executor进程的CPU core数量越多,越能够快速地执行完分配给自己的所有task线程。
* 过多的executors-cores会丢失并发优势
* 过多的exetor-cores会导致单个task内存不足
* 增加申请等待时间和风险

(3)executor-memory

  • 设置每个Executor进程的内存
  • Executor内存的大小,很多时候直接决定了Spark作业的性能,而且跟常见的JVM OOM异常,也有直接的关联。
* 每个task分配内存 = executor-memory/executor-cores
* 内存过小会影响任务正常运行
* 内存太大浪费资源,会影响其他业务

(4)driver-memory

  • 用于设置Driver进程的内存
  • 如果需要使用collect算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM内存溢出的问题。
* 尽量避免使用collect操作
* 避免在driver进行数据操作
* 一般建议4-6G即可
2.2、并行度优化

(1)并行度

计算方式:num-executor*executors-cores

(2)partition分区个数

1、增加partition个数可以减少每个task的数据量
2、partition太多会导致任务过细,总运行时间增加,导致driver维护压力增大
3、对于某些内存不足的场景,增加partition数比增大内存更有效

(3)partition数量如何确定

1、读取数据的默认partition由文件大小、文件存储格式、hdfsblock大小共同决定
2、读取数据partition参数:spark.default.parallelism
3、Join时partition参数:spark.sql.shuffle.partition
4、手动指定stage分区数:repartition
注意:一般partition设置为num-executor*executors-cores*(2-3)
2.3、代码调优
1、数据持久化:对多次使用的RDD进行持久化,下次调用时候不用重新计算
2、避免创建重复的RDD
3、BoradCast:大数据对象考虑广播变量
2.4、算子调优

(1)减少使用shuffle算子

1、尽量避免使用reducebykey、join、repartition等会进行shuffle算子
2、Broadcast小数据与map数据join,避免shuffle

(2)使用高性能算子

待补充
2.5、常用调优参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7JE4AVSv-1627877319822)(C:/Users/%E6%9D%8E%E6%B5%B7%E4%BC%9F/AppData/Roaming/Typora/typora-user-images/image-20210802120214540.png)]
在这里插入图片描述

3、数据倾斜

【问题描述】

大多数任务都完成了,还有那么一两个任务怎么都跑不完或者跑的很慢,

主要分为数据倾斜和task倾斜两种

【问题原因】

  • 在进行shuffle的时候需要将各个节点上的相同的key的数据拉拉取某个节点上的一个task进行处理
  • 若有某个key对应的数据量特别大,则会
    • 导致该task内存不足失败
    • 导致JVM大部分时间在GC,运行异常缓慢

【解决方案】

1.数据倾斜

1、大多数情况是由于大量null值,或者"",或者0值,或者其他非法值引起,在计算前过滤掉这些数;

2、如果是正常热值,可考虑将热值先分离出来单独处理,再将结果合并;

2.任务倾斜

  • task倾斜原因比较多,网络io,cpu,mem都有可能造成这个节点上的任务执行缓慢,可以去看该节点的性能监控来分析原因。
1、增加executor内存
2、增加spark.shuffle.memoryFraction,即增加shuffle占用内存比例
  • 可以开启spark的推测机制,开启推测机制后如果某一台机器的几个task特别慢,推测机制会将任务分配到其他机器执行,最后Spark会选取最快的作为最终结果。
spark.speculation true

spark.speculation.interval 100 - 检测周期,单位毫秒;

spark.speculation.quantile 0.75 - 完成task的百分比时启动推测

spark.speculation.multiplier 1.5 - 比其他的慢多少倍时启动推测。

4、常见问题

4.1、org.apache.spark.shuffle.FetchFailedException

【问题描述】

这种问题一般发生在有大量shuffle操作的时候,task不断的failed,然后又重执行,一直循环下去,非常的耗时。

【报错提示】

missing output location
	org.apache.spark.shuffle.MetadataFetchFailedException: Missing an output location for shuffle 0
shuffle fetch faild
	org.apache.spark.shuffle.FetchFailedException: Failed to connect to spark047215/192.168.47.215:50268 

当前的配置为每个executor使用1cpu,5GRAM,启动了20个executor

【解决方案】

一般遇到这种问题提高executor内存即可,同时增加每个executor的cpu,这样不会减少task并行度。

  • spark.executor.memory 15G
  • spark.executor.cores 3
  • spark.cores.max 21

启动的execuote数量为:7个

  1. execuoteNum = spark.cores.max/spark.executor.cores

每个executor的配置:

  1. 3core,15G RAM

消耗的内存资源为:105G RAM

  1. 15G*7=105G

可以发现使用的资源并没有提升,但是同样的任务原来的配置跑几个小时还在卡着,改了配置后几分钟就结束了。

4.2、Executor&Task Lost

【问题描述】

因为网络或者gc的原因,worker或executor没有接收到executor或task的心跳反馈

【报错提示】

executor lost
	WARN TaskSetManager: Lost task 1.0 in stage 0.0 (TID 1, aa.local): ExecutorLostFailure (executor lost)

task lost
	WARN TaskSetManager: Lost task 69.2 in stage 7.0 (TID 1145, 192.168.47.217): [java.io](http://java.io/).IOException: Connection from /192.168.47.217:55483 closed

各种timeout
	java.util.concurrent.TimeoutException: Futures timed out after [120 second 
  	ERROR TransportChannelHandler: Connection to /192.168.47.212:35409 has been quiet for 120000 ms while there are outstanding requests. Assuming connection is dead; please adjust spark.network.timeout if this is wrong 

【解决方案】

提高 spark.network.timeout 的值,默认是120s,根据情况改成300(5min)或更高,如果没有full gc,建议1200

提高spark.sql.broadcastTimeou,默认是300,建议设置成1200

配置所有网络传输的延时,可设置以下参数,默认覆盖其属性

- spark.core.connection.ack.wait.timeout
- spark.akka.timeout
- spark.storage.blockManagerSlaveTimeoutMs
- [spark.shuffle.io](http://spark.shuffle.io/).connectionTimeout
- spark.rpc.askTimeout or spark.rpc.lookupTimeout
4.3、OOM(内存溢出)

【问题描述】

内存不够,数据太多就会抛出OOM的Exeception

【解决方案】

主要有driver OOM和executor OOM两种

1.driver OOM

一般是使用了collect操作将所有executor的数据聚合到driver导致。尽量不要使用collect操作即可。

2.executor OOM,可以按下面的内存优化的方法增加code使用内存空间

  • 增加executor内存总量,也就是说增加spark.executor.memory的值
  • 增加任务并行度(大任务就被分成小任务了),参考下面优化并行度的方法

【解决方案】

1.内存

如果任务shuffle量特别大,同时OMrdd缓存比较少,可以更改下面的参数进一步提高任务运行速度。

spark.storage.memoryFraction - 分配给rdd缓存的比例,默认为0.6(60%),如果缓存的数据较少可以降低该值。

spark.shuffle.memoryFraction - 分配给shuffle数据的内存比例,默认为0.2(20%)

剩下的20%内存空间则是分配给代码生成对象等。

如果任务运行缓慢,jvm进行频繁gc或者内存空间不足,或者可以降低上述的两个值。

“spark.rdd.compress”,“true” - 默认为false,压缩序列化的RDD分区,消耗一些cpu减少空间的使用

如果数据只使用一次,不要采用cache操作,因为并不会提高运行速度,还会造成内存浪费。

2.并行度

  • spark.default.parallelism 发生shuffle时的并行度,在standalone模式下的数量默认为core的个数,也可手动调整,数量设置太大会造成很多小任务,增加启动任务的开销,太小,运行大数据量的任务时速度缓慢。

  • spark.sql.shuffle.partitions sql聚合操作(发生shuffle)时的并行度,默认为200,如果任务运行缓慢增加这个值。相同的两个任务:

    • spark.sql.shuffle.partitions=300:
    • spark.sql.shuffle.partitions=500:
    • 速度变快主要是大量的减少了gc的时间,修改map阶段并行度主要是在代码中使用rdd.repartition(partitionNum)来操作。

5、问题定位

  • 当难以定位具体问题时
1、观察Spark日志找到阻塞task
2、找到则色task对应的executor host
3、登录对应的机器利用JDK自带监控工具观察jvm运行状况
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随缘清风殇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值