尽管有很多东西,但是火花作业没有RAM(java.lang.OutOfMemoryError)。 xmx太低了?

时间:2016-02-15 13:36:17

标签: 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内存(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"))

1 个答案:

答案 0 :(得分: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)来查看某些记录而不将所有记录都发送给驱动程序。