Scala Spark:读取和写入拼花导致OutOfMemoryError:Java堆空间
我编写了一些代码来读取拼花地板文件,稍微切换模式,然后将数据写入一个新的拼花地板文件。代码如下所示:Scala Spark:读取和写入拼花导致OutOfMemoryError:Java堆空间,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我编写了一些代码来读取拼花地板文件,稍微切换模式,然后将数据写入一个新的拼花地板文件。代码如下所示: ... val schema = StructType( List( StructField("id", LongType, false), StructField("data", ArrayType(FloatType), false) ) ) val data = sqlContext.read.parquet(file.getAbsolutePath) val r
...
val schema = StructType(
List(
StructField("id", LongType, false),
StructField("data", ArrayType(FloatType), false)
)
)
val data = sqlContext.read.parquet(file.getAbsolutePath)
val revisedData = data.map(r => Row(r.getInt(0).toLong, r.getSeq[Float](1)))
val df = sqlContext.createDataFrame(revisedData, schema)
Writer.writeToParquet(df)
Writer
object Writer {
def writeToParquet(df : DataFrame) : Unit = {
val future = Future {
df.write.mode(SaveMode.Append).save(path)
}
Await.ready(future, Duration.Inf)
}
}
对于一个大约4GB的文件,我的程序中断,引发了一个OutOfMemoryError:Java堆空间。我为执行器设置了6GB的内存(使用-Dspark.executor.memory=6g
),提高了JVM堆空间(使用-Xmx6g
),将Kryo序列化程序缓冲区增加到2GB(使用System.setProperty(“spark.kryoserializer.buffer.mb”,“2048”)
)。然而,我仍然得到了错误
这是堆栈跟踪:
java.lang.OutOfMemoryError: Java heap space
at com.esotericsoftware.kryo.io.Output.<init>(Output.java:35)
at org.apache.spark.serializer.KryoSerializer.newKryoOutput(KryoSerializer.scala:76)
at org.apache.spark.serializer.KryoSerializerInstance.output$lzycompute(KryoSerializer.scala:243)
at org.apache.spark.serializer.KryoSerializerInstance.output(KryoSerializer.scala:243)
at org.apache.spark.serializer.KryoSerializerInstance.serialize(KryoSerializer.scala:247)
at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:236)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
java.lang.OutOfMemoryError:java堆空间
在com.esotericsoftware.kryo.io.Output.(Output.java:35)
位于org.apache.spark.serializer.KryoSerializer.newKryoOutput(KryoSerializer.scala:76)
在org.apache.spark.serializer.kryoserializerrinstance.output$lzycompute上(KryoSerializer.scala:243)
位于org.apache.spark.serializer.kryoserializerrinstance.output(KryoSerializer.scala:243)
位于org.apache.spark.serializer.KryoSerializerInstance.serialize(KryoSerializer.scala:247)
位于org.apache.spark.executor.executor$TaskRunner.run(executor.scala:236)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
运行(Thread.java:744)
如何避免此错误?在我的评论之后,有两件事: 1) 您需要注意
spark.kryoserializer.buffer.mb
属性名称,在最新的spark中,他们将其更改为spark.kryoserializer.buffer
和spark.kryoserializer.buffer.max
2) 您必须注意缓冲区的大小和堆的大小,它必须足够大以存储您正在写入的单个记录,但不能太大,因为kryo正在创建一个该大小的显式byte[]
(并且为2GB分配一个byte
数组通常是个坏主意)。尝试使用适当的属性降低缓冲区大小。使用SparkyR,
具有相同的OutOfMemoryError,
尽管减少了spark.kryoserializer.buffer,
无法阅读拼花地板一个我能写的文件,
我的解决办法是:
禁用“急切”:(内存=FALSE)
spark 2.3.0
第1.0.0节
R版本3.4.2首先,您没有在任何地方使用
revisedData
。第二,你的房间到底在哪里?最后,文件的结构是什么(有多少列)?对不起,我已经纠正了代码中的错误。OOM是在com.esotericsoftware.kryo.io.Output.(Output.java:35)
(请参阅更新后的带有堆栈跟踪的帖子)中提出的。原始文件有两列,即Int
和Seq[Float]
列您使用的Spark版本是什么?确保使用适当的kryoserializer缓冲区属性(1.4.1没有mb
one)。我会尽量减少缓冲区大小,2GB太多了。但它需要足够大以容纳数据,所以请检查记录的长度,并尝试使用尽可能小的缓冲区。看起来spark版本使用的是kryo-2.22,它基本上尝试做buffer=newbyte[bufferSize]代码>但是没有那么多空间。是的,现在它可以工作了!我使用了旧版本Spark中的错误缓冲区属性。切换了属性,现在运行平稳。谢谢@naivge ok将其添加为一个答案
spark_read_parquet(sc,name=curName,file.path("file://",srcFile), header=true, memory=FALSE)