我一直在努力学习如何使用Apache Spark,并且我在尝试将Cassandra中的所有值(使用datastax spark-cassandra-connector)中的所有值进行求解时遇到了问题。我尝试的所有内容都会导致 java.lang.OutOfMemoryError:Java堆空间。
这是我提交给spark master的代码:
object Benchmark {
def main( args: Array[ String ] ) {
val conf = new SparkConf()
.setAppName( "app" )
.set( "spark.cassandra.connection.host", "ec2-blah.compute-1.amazonaws.com" )
.set( "spark.cassandra.auth.username", "myusername" )
.set( "spark.cassandra.auth.password", "mypassword" )
.set( "spark.executor.memory", "4g" )
val sc = new SparkContext( conf )
val tbl = sc.cassandraTable( "mykeyspace", "mytable" )
val res = tbl.map(_.getFloat("sclrdata")).sum()
println( "sum = " + res )
}
}
现在我的集群中只有一个spark worker节点,并且鉴于表的大小,并不是所有节点都可以同时存储在内存中。但是我不认为这会是一个问题,因为火花应该懒惰地评估命令,并且总结列中的所有值不应该让整个表一次驻留在内存中。
我是这个主题的新手,所以任何澄清为什么这不起作用或帮助如何正确地做到这一点将非常感激。
由于
答案 0 :(得分:1)
也许spark正在将整个表构建为单个内存分区,以便它可以对其进行映射操作。
我认为spark应该溢出到磁盘而不是抛出OutOfMemoryExceptions,但如果只有一个分区,它可能无法溢出。我看到了类似的问题here,他通过指定这样的分割大小来解决它:
conf = new SparkConf();
conf.setAppName("Test");
conf.setMaster("local[4]");
conf.set("spark.cassandra.connection.host", "192.168.1.15").
set("spark.executor.memory", "2g").
set("spark.cassandra.input.split.size_in_mb", "67108864");
所以尝试在你的conf中设置spark.cassandra.input.split.size_in_mb。
我想这可以让spark总结表中的块,然后在需要空间用于新块时从内存中逐出这些块。
您可以研究的另一件事是为表RDD指定存储级别,以允许它溢出到磁盘。我想你可以通过添加“.persist(StorageLevel.MEMORY_AND_DISK)”来做到这一点。默认值似乎是MEMORY_ONLY。请参阅RDD持久性部分中有关存储级别here的更多信息。