前置
主要涉及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都溢写到磁盘上了,就说明偏少了
2、如果发现shuffle也spill到了memory和disk上时,也说明给shuffle的内存少了
实际中怎么配呢?
1.6之前都是静态的,默认是334的比例。之后引入了统一内存管理,也就是execution和storage之间添加一个缓冲区,可以动态调整。
先测试运行,在sparkUI中看storage和exectuion用到多少,然后可以算出单个task用到的内存,然后结合executor的并行度和core的数量