前置

主要涉及6个参数,从3个方面:executor、core、内存的大小,并行度,内存管理 进行调优

优化的方案

资源分配

num-executors:spark使用多少个executors
executor-cores:core和task的数量
这2个参数要结合一起来配置,还要考虑可用的计算资源,executor-cores设置为2-4个比较合适,num-executors就是总共可用的cores 除以executor-cores。当然,这一切都要在可用范围内

并行度

spark.default.parallelism:同一时刻一个stage运行的task数量,如果num-executors * executor-cores =200,但spark.default.parallelism设成了20,那么180个线程就被浪费了。官方给的建议是num-executors * executor-cores的2-3倍,也就是400-600
executor-memory:一般如果task逻辑复杂,单个task读取数据量比较大,内存就给的高一点

内存管理优化

spark.storage.memoryFraction:如果RDD的持久化,persist和cache比较多的时候,可以设置的高一点
spark.shuffle.memoryFraction:shuffle算子比较多,shuffle数据量大的时候,这个就调高
如果代码逻辑复杂,同时频繁触发JVM的GC,则需要调小上面2个参数

这2个涉及到spark内存管理

https://baijiahao.baidu.com/s?id=1722212256064621583&wfr=spider&for=pc

内存的划分

在executor进程中,内存分为堆内和堆外,堆外是JVM用的,对spark不可见。
堆内是spark来管理的,准确的说是memoryManager模块,共有4种

reserved是预留的

不参与 Spark 内存区域大小的计算

User Memory

主要用于存储 RDD 转换操作所需的数据,比如 lineage。 您可以将在转换中使用的数据结构存储在其中。 这取决于您将在此内存中存储什么以及如何存储。 Spark 完全不考虑你在那里做什么以及你是否遵守这个界限。

unified memory
  • Storage Memory 用于缓存和广播数据
  • executionMemory
    她主要用于存储 shuffle、join、sort、aggregation 等中的临时数据。
    最有可能的是,如果您的 pipeline 运行时间过长,可能存在的问题就在于 execution memory 不足。

如何判断内存不够呢?

去sparkUI或者日志中查看

1、如果发现RDD都溢写到磁盘上了,就说明偏少了

spark调优参数 spark调优方法_spark


2、如果发现shuffle也spill到了memory和disk上时,也说明给shuffle的内存少了

spark调优参数 spark调优方法_big data_02

实际中怎么配呢?

1.6之前都是静态的,默认是334的比例。之后引入了统一内存管理,也就是execution和storage之间添加一个缓冲区,可以动态调整。

spark调优参数 spark调优方法_大数据_03

先测试运行,在sparkUI中看storage和exectuion用到多少,然后可以算出单个task用到的内存,然后结合executor的并行度和core的数量