Java 缓存()/persist()的apache spark内存消耗

Java 缓存()/persist()的apache spark内存消耗,java,garbage-collection,apache-spark,Java,Garbage Collection,Apache Spark,当我尝试缓存()或持久化(仅限内存)我的RDD时,我的spark群集挂起。它工作得很好,计算结果大约需要7分钟。如果我不使用cache() 我有6个c3.xlarge EC2实例(4个核,每个7.5 GB RAM),总共有24个核和37.7 GB 我在master上使用以下命令运行应用程序: SPARK\u MEM=5g MEMORY\u FRACTION=“0.6”SPARK\u HOME=“/root/SPARK”java-cp./uber offline.jar:/root/SPARK/a

当我尝试缓存()或持久化(仅限内存)我的RDD时,我的spark群集挂起。它工作得很好,计算结果大约需要7分钟。如果我不使用cache()

我有6个c3.xlarge EC2实例(4个核,每个7.5 GB RAM),总共有24个核和37.7 GB

我在master上使用以下命令运行应用程序:

SPARK\u MEM=5g MEMORY\u FRACTION=“0.6”SPARK\u HOME=“/root/SPARK”java-cp./uber offline.jar:/root/SPARK/assembly/target/scala-2.10/SPARK-assembly\u 2.10-0.9.0-incubating-hadoop1.0.4.jar pl.instream.dsp.offline.OfflineAnalysis

该数据集大约有50GB的数据被划分为24个文件。我将其压缩并存储在S3存储桶中的24个文件中(每个文件的大小为7MB到300MB)

我绝对找不到集群出现这种行为的原因,但似乎spark耗尽了所有可用内存,进入了GC收集循环。当我查看gc详细信息时,我可以找到如下循环:

[GC 5208198K(5208832K), 0,2403780 secs]
[Full GC 5208831K->5208212K(5208832K), 9,8765730 secs]
[Full GC 5208829K->5208238K(5208832K), 9,7567820 secs]
[Full GC 5208829K->5208295K(5208832K), 9,7629460 secs]
[GC 5208301K(5208832K), 0,2403480 secs]
[Full GC 5208831K->5208344K(5208832K), 9,7497710 secs]
[Full GC 5208829K->5208366K(5208832K), 9,7542880 secs]
[Full GC 5208831K->5208415K(5208832K), 9,7574860 secs]
这最终会产生如下信息:

WARN storage.BlockManagerMasterActor: Removing BlockManager BlockManagerId(0, ip-xx-xx-xxx-xxx.eu-west-1.compute.internal, 60048, 0) with no recent heart beats: 64828ms exceeds 45000ms
…并阻止计算机的任何进步。看起来内存消耗了100%,但我试着使用RAM更多的机器(比如每个30GB),效果是一样的


这种行为的原因可能是什么??有人能帮忙吗???

尝试使用更多分区,每个CPU应该有2-4个分区。IME增加分区的数量通常是使程序更稳定(通常更快)的最简单方法

默认情况下,我认为您的代码将使用24个分区,但对于50GB的数据来说,这太少了。我会尝试至少100个分区

接下来,您将使用
SPARK\u MEM=5g
,但假设每个节点都有7.5gb,因此您最好使用
SPARK\u MEM=7500m

你也可以试着增加记忆分数,但我认为上面的方法更有帮助


一般要点:对您的文件使用HDFS而不是s3,它的速度要快得多。确保在缓存数据之前正确地咀嚼数据-例如,如果您有100列的TSV数据,但只使用了10个字段,那么请确保在尝试缓存之前提取了这些字段。

原始缓存和序列化缓存之间有很大区别

  • 原始缓存:(
    rdd.cache()
    rdd.persist(仅限org.apache.spark.storage.StorageLevel.MEMORY)

    这将消耗2-3倍的内存。例如,一个100MB的rdd可以消耗350MB的内存

  • 序列化缓存(rdd.persist(org.apache.spark.storage.StorageLevel.MEMORY_ONLY_SER))

    这将消耗几乎相同的内存量和一些小的开销。例如,100MB的数据将在内存中消耗100MB+几KB

  • 在操作过程中,原始缓存速度更快。序列化缓存需要更长的时间(因为在计算之前必须对对象进行反序列化)

    这是我的研究得出的一个有趣的结果


    您的应用程序持续执行GC,内存恢复非常少,某些配置/编码错误,导致它填充内存-这也是我从日志中看到的。问题是它为什么会发生。@Bartek如果没有实际的代码,真的很难说。。但是,50GB的文件太多了。如果你一次加载所有这些内容并试图处理,当然你会有严重的记忆压力。@Eugene谢谢你的回答。据我所知,ApacheSpark应该处理如此大量的数据,并将部分数据缓存在磁盘上,或者在内存出现问题时重新读取。我没有写代码,因为我认为我的代码中没有bug,这1)非常简单;2) 如果我不缓存/持久化,工作正常。如果你觉得有用的话,我可以粘贴它。试着在缓存中放入一些数据,比如说100万个样本,看看Spark web UI上的内存消耗情况,然后你应该找到你需要的总内存。谢谢,coalesce听起来是一个很好的尝试方向。我会检查一下,然后告诉你结果。合并(500,true)可能是一个好的选择吗?在cache()之前添加合并(500,true)会有所帮助。似乎GC问题已经解决了。您对24个默认分区的假设来自哪里?S3中的文件数?核心的总数?@EricEijkelenboom是的,文件的数量。如果您发现确实重复,请将其标记为重复。