针对检查点/缓存作业的EMR“超出内存限制”

时间:2017-10-17 00:30:44

标签: caching memory-leaks garbage-collection apache-spark-2.0 checkpointing

我对缓存的理解是错误的吗?在我所有的转换之后产生的RDD非常小,比如1 GB。它的计算数据非常大,大小约为700 GB。

我必须运行逻辑来读取成千上万个相当大的文件,所有这些都是为了计算出更小的结果RDD。每次迭代都会处理下一批400个文件,这些文件在读入时可以放大到大约700 GB。以相同的方式处理(读取和转换)传入的RDD,然后与累积的RDD联合。我在每次迭代后缓存和检查点(也 unpersisting(with blocking = true)旧版本的rdd)以便我可以剪切RDD血统,以便我如果出现问题,将不必重新计算结果,并节省执行程序的空间。 所以,我认为在任何时候我真的只需要1 GB *迭代次数+约750 GB的内存总量,而且1.6 TB应该绰绰有余。但显然我误解了东西。

在每次迭代中,GC时间越来越长。 Spark UI显示执行程序处于红色区域(> 10%的时间花在GC上)。整个工作可能会在第3次或第4次迭代时失败,其中包含 MemoryLimit超出 Lost Executor /没有执行者路径等消息,并且YARN会终止执行程序。我认为通过缓存和检查点,我在执行器上节省了大量空间。我只是不明白是否存在某种内存泄漏? 为什么内存会继续填满?

我正在使用m3.large实例在EMR上运行Spark 2.1.1。我的群集大小限制在约1.6 TB。我使用以下配置运行:

driver-memory 8g
deploy-mode cluster 
spark.dynamicAllocation.enabled=true 
spark.dynamicAllocation.minExecutors=100 
spark.dynamicAllocation.maxExecutors=200
spark.shuffle.service.enabled=true 
executor-cores 4 
executor-memory 8g 

我的代码看起来像什么:

var accRdd = <empty>
val batchSize = 400
var iteration = 1
filesToIngest.grouped(batchSize).foreach {
    val transformedRdd = transform(accRdd).reduceByKey((row1, row2) => 
      combine(row1, row2)
    )
    val oldAccRdd = accRdd
    accRdd = accRdd.union(transformedRdd).reduceByKey((row1, row2) => 
      combine(row1, row2)
    ).coalesce(5 + i)
    accRdd.persist(MEMORY_AND_DISK_SER)
    accRdd.checkpoint()
    oldAccRdd.unpersist(blocking = true) // I assume this will ensure all references to this cleared from memory
    log_info(s"Total row count on iteration: ${accRdd.count()}")
    iteration += 1
}

我遵循了这个建议:https://github.com/deeplearning4j/nd4j/issues/1251,我试图避免调整与gc,内存分数和jvm相关的其他配置变量。同样,我正在寻找可能发生的事情的解释,以及我对缓存/检查点的假设可能是错误的。 谢谢!

1 个答案:

答案 0 :(得分:0)

您可能希望查看内存页面中的一些建议: https://deeplearnin4j.org/memory

https://deeplearning4j.org/spark

通常,deeplearning4j有自己的off heap内存。您应该使用更多执行程序设置较小的批处理大小,注意javacpp关闭堆配置并将允许的火花存储器设置在头上。