繁体   English   中英

Apache Spark DataFrame导致内存不足

[英]apache spark dataframe causes out of memory

我的应用程序在微小对象的大型数据集上运行良好。 但是随着对象的增长,对数据帧的操作会遇到内存不足异常。 基本上,应用程序读取序列文件,然后将键/值转换为具有某些列的行对象,进行一些排序,最后转换回rdd以编写序列文件。

如果行对象很小-大约20 KB的数据-一切都很好。 在第二次运行中,行对象包含大约2mb的数据,并且spark遇到内存不足的问题。 我测试了几个选项,更改了分区的大小和数量,但是应用程序运行不稳定。

为了重现此问题,我创建了以下示例代码。 将rd个10000个int对象映射到长度为2mb的字符串(概率为4mb,假设每个字符16位)。 10.000乘2mb约为20gb的数据。 show()排序操作和show()操作再次按预期工作。 日志表明spark正在存储到磁盘。 但是,当将结果写入csv文件,hadoop文件或仅调用JavaRDD()时,应用程序将以内存不足结尾:Java堆空间似乎spark仅在内存中保存数据。

// create spark session
SparkSession spark = SparkSession.builder()
        .appName("example1")
        .master("local[2]")
        .config("spark.driver.maxResultSize","0")
        .getOrCreate();

JavaSparkContext sc = JavaSparkContext.fromSparkContext(spark.sparkContext());

// base to generate huge data
List<Integer> list = new ArrayList<>();
for (int val = 1; val < 10000; val++) {
    int valueOf = Integer.valueOf(val);
    list.add(valueOf);
}
// create simple rdd of int
JavaRDD<Integer> rdd = sc.parallelize(list,200);
// use map to create large object per row
JavaRDD<Row> rowRDD =
        rdd.map(value -> RowFactory.create(String.valueOf(value), createLongText(UUID.randomUUID().toString(), 2 * 1024 * 1024)))
        ;

StructType type = new StructType();
type = type
        .add("c1", DataTypes.StringType)
        .add( "c2", DataTypes.StringType );

Dataset<Row> df = spark.createDataFrame(rowRDD, type);
// works
df.show();
df = df.sort( col("c2").asc() );
// takes a lot of time but works
df.show();
// OutOfMemoryError: java heap space
df.write().csv("d:/temp/my.csv");
// OutOfMemoryError: java heap space
df
        .toJavaRDD()
        .mapToPair(row -> new Tuple2(new Text(row.getString(0)), new Text( row.getString(1))))
        .saveAsHadoopFile("d:\\temp\\foo", Text.class, Text.class, SequenceFileOutputFormat.class );

操作createLongText()创建一个长字符串。

private static String createLongText( String text, int minLength ) {
    String longText = text;
    while( longText.length() < minLength ) {
        longText = longText + longText;
    }
    return longText;
}

JVM在Java 1.8u171中具有4GB的堆(-Xms4g -Xmx4g),具有默认GC(GC1),并且在本地模式下与-XX:+ UseParallelGC可选运行。 堆大小朝着上限增加,并且gc活性增加。 在大多数情况下,oom使驱动程序崩溃,在某些情况下,高gc活动导致驱动程序超时。 这是spark.driver.maxResultSize首次设置为0(无限制)。 当使用较小的对象(几乎相同数量的数据,具有较少数据的更多对象)时,任何对象都可以正常工作。 似乎从dataFrame到rdd的任何转换都会绑定许多内存资源,并强制将所有结果发送回驱动程序。 我在崩溃之前创建了一个堆转储,并看到了一个大型的scala数组数组。 内部数组包含约32mb(分区大小!?),内部数组的总和约为分区数(115)

8/07/26 21:58:31 INFO MemoryStore: Block taskresult_144 stored as bytes in memory (estimated size 47.7 MB, free 86.3 MB)
18/07/26 21:58:31 INFO BlockManagerInfo: Added taskresult_144 in memory on blackhawk:61185 (size: 47.7 MB, free: 86.4 MB)
18/07/26 21:58:31 INFO Executor: Finished task 143.0 in stage 1.0 (TID 144). 50033768 bytes result sent via BlockManager)
18/07/26 21:58:31 INFO TaskSetManager: Starting task 145.0 in stage 1.0 (TID 146, localhost, executor driver, partition 145, PROCESS_LOCAL, 8355 bytes)
18/07/26 21:58:31 INFO Executor: Running task 145.0 in stage 1.0 (TID 146)
18/07/26 21:58:35 INFO TaskSetManager: Finished task 104.0 in stage 1.0 (TID 105) in 36333 ms on localhost (executor driver) (105/200)
18/07/26 21:58:35 ERROR Executor: Exception in task 144.0 in stage 1.0 (TID 145)
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3236)
    at java.lang.StringCoding.safeTrim(StringCoding.java:79)
    at java.lang.StringCoding.encode(StringCoding.java:365)
    at java.lang.String.getBytes(String.java:941)
    at org.apache.spark.unsafe.types.UTF8String.fromString(UTF8String.java:141)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$SpecificUnsafeProjection.StaticInvoke_1$(Unknown Source)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$SpecificUnsafeProjection.apply(Unknown Source)
    at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder.toRow(ExpressionEncoder.scala:288)
    at org.apache.spark.sql.SparkSession$$anonfun$4.apply(SparkSession.scala:592)
    at org.apache.spark.sql.SparkSession$$anonfun$4.apply(SparkSession.scala:592)

知道这里有什么问题吗? 还是Spark 2.3.1中的错误?

尝试不要使用GC1垃圾程序,这可能是连续内存分配和GC1 32mb区域的错误。

请阅读http://labs.criteo.com/2018/01/spark-out-of-memory/ ,可能是这样吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM