将大表从mongodb加载到spark时出现堆栈溢出错误

时间:2016-06-29 10:08:11

标签: mongodb scala apache-spark

全部    我在mongodb有一张大约1TB的桌子。我尝试使用mongo连接器将它加载到spark中,但是在执行18分钟后我一直在堆栈溢出。

java.lang.StackOverflowError:
at scala.collection.TraversableLike$$anonfun$filter$1.apply(TraversableLike.scala:264)
at scala.collection.MapLike$MappedValues$$anonfun$foreach$3.apply(MapLike.scala:245)
at scala.collection.MapLike$MappedValues$$anonfun$foreach$3.apply(MapLike.scala:245)
at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:772)
....
at scala.collection.MapLike$MappedValues$$anonfun$foreach$3.apply(MapLike.scala:245)
at scala.collection.MapLike$MappedValues$$anonfun$foreach$3.apply(MapLike.scala:245)
at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:772)
16/06/29 08:42:22 INFO YarnAllocator: Driver requested a total number of 54692 executor(s).
16/06/29 08:42:22 INFO YarnAllocator: Will request 46501 executor containers, each with 4 cores and 5068 MB memory including 460 MB overhead

是因为我没有提供足够的内存吗?或者我应该提供更多存储? 我试图添加检查点,但它没有帮助。 我在代码中更改了一些值,因为它们与我的公司数据库有关,但整个代码仍然适用于这个问题。

val sqlContext = new SQLContext(sc)

val builder = MongodbConfigBuilder(Map(Host -> List("mymongodurl:mymongoport"), Database -> "mymongoddb", Collection ->"mymongocollection", SamplingRatio -> 0.01, WriteConcern -> "normal"))
val readConfig = builder.build()

val mongoRDD = sqlContext.fromMongoDB(readConfig)
mongoRDD.registerTempTable("mytable")

val dataFrame = sqlContext.sql("SELECT u_at, c_at FROM mytable")
val deltaCollect = dataFrame.filter("u_at is not null and c_at is not null and u_at != c_at").rdd
val mapDelta = deltaCollect.map {
  case Row(u_at: Date, c_at: Date) =>{
    if(u_at.getTime == c_at.getTime){
      (0.toString, 0l)
    }
    else{
      val delta = ( u_at.getTime - c_at.getTime ) / 1000/60/60/24
      (delta.toString, 1l)
    }
  }
}
val reduceRet = mapDelta.reduceByKey(_+_)

val OUTPUT_PATH = s"./dump"
reduceRet.saveAsTextFile(OUTPUT_PATH)

2 个答案:

答案 0 :(得分:3)

如您所知,Apache Spark在执行作业时执行内存处理,即将要处理的数据加载到内存中。根据您的问题和评论,您有一个大到1TB的数据集,Spark可用的内存大约为每个核心8GB。因此,在这种情况下,您的spark执行器将永远是内存不足的。

为避免这种情况,您可以按照以下两个选项之一进行操作:

  1. 将您的RDD Storage Level更改为MEMORY_AND_DISK。通过这种方式,Spark不会将完整数据加载到其内存中;相反,它会尝试将额外的数据泄漏到磁盘中。但是,由于内存和磁盘之间的事务处理,性能会降低。查看RDD persistence
  2. 增加核心内存,以便Spark甚至可以将1TB数据完全加载到内存中。这样性能会很好,但基础设施成本会增加。

答案 1 :(得分:1)

我添加了另一个java选项" -Xss32m"激发驱动程序为每个线程提高堆栈的内存,而这个异常不再抛出。我是多么愚蠢,我应该早点尝试过。但是显示了另一个问题,我将不得不检查更多。还是非常感谢你的帮助。