spark是否在内存中加载RDD

时间:2016-02-18 08:36:36

标签: scala apache-spark

我是Spark的新手。需要帮助了解火花的工作原理。 假设README.md存储在3个节点的HDFS 128块中,我使用spark shell来处理它。

val textFile = sc.textFile("README.md")
val linesWithSpark = textFile.filter(line => line.contains("Spark"))
linesWithSpark.first()

在上述情况下,执行将由第3行触发。

Spark会在HDFS节点的RAM中加载完成README.md的3次拆分,然后过滤linesWithSpark并保留在内存中一会儿。并从linesWithSpark(从第一次拆分)发送第一行? 或者它只会用" Spark"拉出第一行。来自HDFS节点磁盘的Split1并将其发送给驱动程序。

如果我将第二行更改为

,处理会有什么变化
val linesWithSpark = textFile.filter(line => line.contains("Spark")).cache()

1 个答案:

答案 0 :(得分:1)

让我们从一个简单的实验开始。首先让我们加载数据并检查其分布:

val textFile = sc.textFile("README.md", 2)
textFile.glom.map(_.size).collect
// Array[Int] = Array(54, 41)

我们可以怀疑简单filter只生成一个任务:

textFile.filter(line => line.contains("Spark")).toDebugString
// String = 
// (2) MapPartitionsRDD[11] at filter at <console>:30 []
//  |  MapPartitionsRDD[8] at textFile at <console>:27 []
//  |  README.md HadoopRDD[7] at textFile at <console>:27 []

现在让我们在没有cache的情况下运行这个工作并收集一些诊断信息:

val cnt = sc.accumulator(0L, "cnt")

val linesWithSpark = textFile.filter(line => {
  cnt += 1L
  line.contains("Spark")
})

linesWithSpark.first()
// String = # Apache Spark
cnt.value
/// Long = 1

正如您所见,没有缓存的作业只会处理一条记录。这是因为first作为take(1)执行。在第一次迭代中,take仅运行作业on a one partition并在其迭代器上使用it.take(left),其中left等于1。

由于Iterators是惰性的,我们的程序在处理第一行后立即返回。如果第一个分区没有提供所需的结果take迭代,则每次迭代都会增加已处理分区的数量。

接下来让我们用缓存重复相同的实验:

val cacheCntCache = sc.accumulator(0L, "cacheCnt")

val linesWithSparkCached = textFile.filter(line => {
  cacheCntCache  += 1L
  line.contains("Spark")
}).cache()

linesWithSparkCached.first()
// String = # Apache Spark
cacheCntCache.value
// Long = 54

此外,让我们检查存储信息:

sc.getRDDStorageInfo
// Array[org.apache.spark.storage.RDDInfo] = Array(
//   RDD "MapPartitionsRDD" (12)
//   StorageLevel: StorageLevel(false, true, false, true, 1); 
//   CachedPartitions: 1; TotalPartitions: 2; MemorySize: 1768.0 B; 
//   ExternalBlockStoreSize: 0.0 B; DiskSize: 0.0 B)

正如您所看到的,如果缓存Spark将完成处理分区并将其缓存在内存中。虽然我无法提供导致此行为的确切部分源,但它看起来像是一个合理的优化。由于分区已经加载,因此没有理由停止工作。

另请参阅:Lazy foreach on a Spark RDD