我正在使用我的Spark作业获取java.lang.OutOfMemoryError,即使只有20%的内存正在使用中。
我尝试了几种配置:
我的数据集由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"))
答案 0 :(得分:4)
问题的根源在于您应该尝试将更多I / O卸载到分布式任务,而不是在驱动程序和工作任务之间来回传送。虽然有时可能并不明显哪些调用是驱动程序本地的,哪些调用描述了分布式操作,但经验法则包括避免parallelize
和collect
,除非您绝对需要在一个地方使用所有数据。您可以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)
来查看某些记录而不将所有记录都发送给驱动程序。