Apache spark 使用缓存触发堆内存扩展

Apache spark 使用缓存触发堆内存扩展,apache-spark,pyspark,Apache Spark,Pyspark,我正在努力使我的Spark程序避免超过线程内存限制(在执行器上)。 我得到的“已知”错误是: Container killed by YARN for exceeding memory limits. 3.8 GB of 3.6 GB physical memory used. 我不想仅仅提高执行器内存、执行器内存开销或优化资源或分区,而是想知道堆外内存为什么在扩展 我正在使用pysparkv2.4.4,据我所知,线程内存开销(对于执行器)是由我的Spark程序(JVM外部)分配的任何堆外内

我正在努力使我的Spark程序避免超过线程内存限制(在执行器上)。
我得到的“已知”错误是:

Container killed by YARN for exceeding memory limits.  3.8 GB of 3.6 GB physical memory used.
我不想仅仅提高执行器内存、执行器内存开销或优化资源或分区,而是想知道堆外内存为什么在扩展

我正在使用pyspark
v2.4.4
,据我所知,线程内存开销(对于执行器)是由我的Spark程序(JVM外部)分配的任何堆外内存

我所知道的唯一额外的“非相关”堆外内存是Python内存,它不是Spark内存开销的一部分:

已确定容器对正在运行的执行器的最大内存大小 通过spark.executor.memoryOverhead,spark.executor.memory的总和, spark.memory.offHeap.size和spark.executor.pyspark.memory

我在程序中使用了大量缓存;禁用
persist
调用以某种方式解决了内存开销问题(较少的执行器死亡,程序最终可以完成),但由于此数据应仅在JVM/磁盘内针对执行内存进行管理,因此不应使用任何堆外内存

由于默认情况下禁用了堆外模式(
spark.memory.offHeap.use
),哪些情况可能会导致内存开销增加,为什么在我的程序中禁用缓存有助于减少开销大小

编辑
使用更大的执行器(两倍于内存和内核)也可以解决这一问题。

JVM上更大的内存意味着更大的开销(大于386m时为10%),这是有道理的,但我们仍然在这个JVM上使用2个内核(即2个任务),我不知道在哪些情况下内存开销会增加。

Spark可能会在无序移动和缓存块传输期间使用堆外内存。;即使
spark.memory.offHeap.use=false

该问题也在(分钟4:05)中提到

Spark 3.0.0及以上版本 由于Spark
3.0.0
Spark.network.io.preferDirectBufs=false一起使用,因此可以禁用此行为

对此进行简要说明:

如果启用,则堆外缓冲区分配是首选的 共享分配器。堆外缓冲区用于减少垃圾 洗牌和缓存块传输期间的收集。用于环境 当堆外内存受到严格限制时,用户可能希望将其关闭 关闭以强制所有分配都在堆上

火花<3.0.0 对于低于
3.0.0
的版本,使用更大的执行器和修改后的更高内存开销可以显著解决此问题,同时保持每个执行器分配的内存相同,以及Spark作业的总体资源消耗相同。
例如:

之前:

spark.executor.cores=1
spark.executor.memory=2g
spark.executor.cores=4
spark.executor.memory=6g
spark.executor.memoryOverhead=3g
容器总内存:2g+384m(最小开销)=
2.375g

每个核心的执行器内存:
2.375g

每个内核的JVM内存:
2g

之后:

spark.executor.cores=1
spark.executor.memory=2g
spark.executor.cores=4
spark.executor.memory=6g
spark.executor.memoryOverhead=3g
容器总内存:6g+3g=
9g

每个核心的执行器内存:
2.25g

每个内核的JVM内存:
1.5g

如果您的容器被纱线弄死(如本Q),有目的的更改应该会有所帮助,但请注意,这是与其他事物的权衡:
每个内核的总体JVM内存较低,因此用户内存(主要是您在执行器中创建的对象)和Spark内存(执行内存和存储内存)中的内存瓶颈更容易出现。
超出的Spark内存通常会溢出到磁盘(具有额外的非相关复杂性),因此会牺牲性能,而用户内存不足可能会导致执行器中的OutOfMemory错误,因此请小心