1

我的 Spark 作业出现 java.lang.OutOfMemoryError,即使只有 20% 的总内存在使用中。

我尝试了几种配置:

  • 1x n1-highmem-16 + 2x n1-highmem-8
  • 3x n1-highmem-8

我的数据集包含 180 万条记录,从主节点上的本地 json 文件中读取。整个json格式的数据集是7GB。我正在尝试执行的工作涉及一个简单的计算,然后是一个 reduceByKey。没什么特别的。这项工作在我只有 32GB 内存 (xmx28g) 的单台家用计算机上运行良好,尽管它需要对磁盘进行一些缓存。

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

堆栈跟踪和 Spark 配置可以在这里查看:https ://pastee.org/sgda

编码

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"))
4

1 回答 1

4

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

在您的情况下,短期解决方案是尝试通过spark-submit --conf spark.driver.memory=40g ...或在该范围内的东西。Dataproc 默认将不到四分之一的机器分配给驱动程序内存,因为通常集群必须支持运行多个并发作业,并且还需要在主节点上为 HDFS 名称节点和 YARN 资源管理器留出足够的内存。

从长远来看,您可能想尝试如何将 JSON 数据直接加载为 RDD,而不是将其加载到单个驱动程序中并parallelize用于分发它,因为这样您可以通过加载任务来显着加快输入读取时间并行数据(并且还消除了Stage 0 contains a task of very large size可能与将大数据从驱动程序传输到工作任务有关的警告)。

类似地,collect您可以以分布式方式进行保存,而不是然后在驱动程序上完成操作sc.saveAsTextFile,而不会在一个地方遇到瓶颈。

读取输入,sc.textFile假设行分隔的 JSON,您可以在某些map任务中进行解析,或者您可以尝试使用 sqlContext.read.json。出于调试目的,它通常就足够了,而不是collect()仅仅调用take(10)来查看一些记录而不将所有记录发送给驱动程序。

于 2016-02-16T05:27:26.297 回答