Apache spark Spark作业脱离RAM(java.lang.OutOfMemoryError),即使存在';太多了。xmx太低了?

Apache spark Spark作业脱离RAM(java.lang.OutOfMemoryError),即使存在';太多了。xmx太低了?,apache-spark,google-cloud-platform,google-cloud-dataproc,Apache Spark,Google Cloud Platform,Google Cloud Dataproc,我的Spark作业中出现了java.lang.OutOfMemoryError,尽管只有20%的内存在使用 我尝试了几种配置: 1x n1-highmem-16+2x n1-highmem-8 3x n1-highmem-8 我的数据集由1.8M记录组成,这些记录从主节点上的本地json文件读取。json格式的整个数据集是7GB。我试图执行的工作包括一个简单的计算,然后是一个reduceByKey。没什么特别的。虽然需要一些磁盘缓存,但该作业在只有32GB ram(xmx28g)的单台家用计

我的Spark作业中出现了java.lang.OutOfMemoryError,尽管只有20%的内存在使用

我尝试了几种配置:

  • 1x n1-highmem-16+2x n1-highmem-8
  • 3x n1-highmem-8
我的数据集由1.8M记录组成,这些记录从主节点上的本地json文件读取。json格式的整个数据集是7GB。我试图执行的工作包括一个简单的计算,然后是一个reduceByKey。没什么特别的。虽然需要一些磁盘缓存,但该作业在只有32GB ram(xmx28g)的单台家用计算机上运行良好

作业通过spark submit在服务器本地(SSH)提交

可以在此处查看堆栈跟踪和Spark配置:

代码

val rdd = sc.parallelize(Json.load()) // load everything
  .map(fooTransform)                  // apply some trivial transformation
  .flatMap(_.bar.toSeq)               // flatten results
  .map(c => (c, 1))                   // count 
  .reduceByKey(_ + _)
  .sortBy(_._2)
log.v(rdd.collect.map(toString).mkString("\n"))

问题的根源在于,您应该尝试将更多的I/O卸载到分布式任务,而不是在驱动程序和辅助任务之间来回传送。虽然有时不太清楚哪些调用是驱动程序本地调用,哪些调用描述了分布式操作,但经验法则包括避免
并行化
收集
,除非您绝对需要将所有数据放在一个位置。在任何可能的最大机器类型下,您可以
Json.load()
parallelize
的数据量都将达到最大值,而像
sc.textFile
这样的调用在理论上可以扩展到数百TB甚至PBs,没有问题

在您的情况下,短期的解决方法是尝试传递
spark submit--conf spark.driver.memory=40g…
或该范围内的其他信息。Dataproc默认为驱动程序内存分配不到机器的四分之一,因为集群通常必须支持运行多个并发作业,并且还需要在主节点上为HDFS namenode和纱线资源管理器保留足够的内存

从长远来看,您可能希望尝试如何直接将JSON数据作为RDD加载,而不是将其加载到单个驱动程序中,然后使用
parallelize
来分发它,因为这样可以通过让任务并行加载数据,大大加快输入读取时间(同时,消除警告
阶段0包含一个非常大的任务
,这可能与将大数据从驱动程序传送到工作任务有关)

类似地,您可以执行类似于
sc.saveAsTextFile
的操作,以分布式方式进行保存,而不必在单个位置进行瓶颈限制,而不是
collect
然后在驱动程序上完成操作


将输入读取为
sc.textFile
将采用行分隔的JSON,您可以在一些
map
任务中进行解析,也可以尝试使用。出于调试目的,通常不使用
collect()
来调用
take(10)
查看一些记录而不将其全部发送给驱动程序。

问题的根源在于,您应该尝试将更多的I/O卸载到分布式任务,而不是在驱动程序和工作任务之间来回发送。虽然有时可能不清楚哪些调用是驱动程序本地调用,哪些调用是非本地调用描述一个分布式操作,经验法则包括避免
parallelize
collect
,除非您绝对需要将所有数据放在一个位置。您可以
Json.load()的数据量
并行化
将在任何可能的最大机器类型下最大化,而使用诸如
sc.textFile
之类的调用理论上可以扩展到数百TB甚至PBs,没有问题

在您的情况下,短期修复方法是尝试传递
spark submit--conf spark.driver.memory=40g…
或该范围内的内容。Dataproc默认情况下,将不到四分之一的计算机分配给驱动程序内存,因为集群通常必须支持运行多个并发作业,并且还需要在m上保留足够的内存用于HDFS名称节点和纱线资源管理器的aster节点

从长远来看,您可能希望尝试如何直接将JSON数据作为RDD加载,而不是将其加载到单个驱动程序中,然后使用
parallelize
来分发它,因为这样可以通过让任务并行加载数据,大大加快输入读取时间(同时,消除警告
阶段0包含一个非常大的任务
,这可能与将大数据从驱动程序传送到工作任务有关)

类似地,您可以执行类似于
sc.saveAsTextFile
的操作,以分布式方式进行保存,而不必在单个位置进行瓶颈限制,而不是
collect
然后在驱动程序上完成操作


将输入读取为
sc.textFile
将采用行分隔的JSON,您可以在一些
map
任务中进行解析,也可以尝试使用。出于调试目的,通常不使用
collect()
来调用
take(10)
在不将所有记录发送给驱动程序的情况下查看一些记录。

您能展示一下如何在节点之间分发RDD-s吗?这是我第一次使用多个节点。我添加了一段相关的Spark代码。我需要手动对其进行分区吗?如果我误解了您的问题,很抱歉。我仍然很抱歉挣钱。你能展示一下你是如何在节点之间分配RDD-s的吗?这是我第一次处理的不仅仅是一个节点。我添加了一段相关的Spark代码。我需要手动划分吗?如果我误解了你的问题,我很抱歉。我还在学习。哦,天哪,你说得很有道理。结果我真的不明白我认为两者都是以一种类似于sc.textFile的方式工作的——但是是的