Spark应用程序遇到问题。这是我的代码的简化版本:
def main(args: Array[String]) {
// Initializing spark context
val sc = new SparkContext()
val nbExecutors = sc.getConf.getInt("spark.executor.instances", 3)
System.setProperty("spark.sql.shuffle.partitions", nbExecutors.toString)
// Getting files from TGZ archives
val archivesRDD: RDD[(String,PortableDataStream)] = utils.getFilesFromHDFSDirectory("/my/dir/*.tar.gz") // This returns an RDD of tuples containing (filename, inpustream)
val filesRDD: RDD[String] = archivesRDD.flatMap(tgzStream => {
logger.debug("Getting files from archive : "+tgzStream._1)
utils.getFilesFromTgzStream(tgzStream._2)
})
// We run the same process with 3 different "modes"
val modes = Seq("mode1", "mode2", "mode3")
// We cache the RDD before
val nb = filesRDD.cache().count()
logger.debug($nb + " files as input")
modes.map(mode => {
logger.debug("Processing files with mode : " + mode)
myProcessor.process(mode, filesRDD)
})
filesRDD.unpersist() // I tried with or without this
[...]
}
生成的日志为(例如输入3个档案):
从存档中获取文件:a
从存档中获取文件:b
从存档中获取文件:c
3个文件作为输入
以以下模式处理文件:mode1
从存档中获取文件:a
从存档中获取文件:b
从存档中获取文件:c
以以下模式处理文件:mode2
从存档中获取文件:a
从存档中获取文件:b
从存档中获取文件:c
以以下模式处理文件:mode3
从存档中获取文件:a
从存档中获取文件:b
从存档中获取文件:c
我的Spark配置:
我从这些日志中了解到的是,文件提取是一次读取的4倍!显然,这导致我遇到了堆空间问题和性能泄漏...
我做错什么了吗?
编辑:我也尝试使用modes.foreach(...)
代替地图,但没有做任何更改...
答案 0 :(得分:0)
您是否尝试过将modes.map
结果传递给List构造函数(即List(modes.map{ /*...*/})
)?有时(我不确定何时),Scala集合会延迟评估映射,因此,如果直到spark删除缓存后才对这些评估进行评估,就必须重新计算。
答案 1 :(得分:0)
好的,经过大量测试,我终于解决了这个问题。实际上有两个问题:
我低估了输入数据的大小:如果RDD太大而无法完全存储在60%的RDD中,Spark的cache
或persist
函数的效率会降低。总内存,我知道,但以为我的输入数据不是很大,但实际上我的RDD是80GB。但是我的60%的内存(即160GB)仍然超过80GB,那么怎么了?在第2个问题中回答...
我的分区太大:在我的代码中的某个地方,RDD的分区数设置为100,所以我有100个分区,每个分区1.6GB。问题是我的数据是由数十个Meg组成的字符串组成的,因此我的分区未满,实际上10GB的已用内存仅包含7GB或8GB的真实数据。
要解决这些问题,我不得不使用persist(StorageLevel.MEMORY_SER)
,这会增加计算时间,但会大大减少内存使用量(according to this benchmark),并将分区号设置为1000(根据Spark文档,建议分区为〜)。 128MB)