走进spark(二) rdd.persisit
上篇我们讲到通过调用rdd.checkpoint,可以将rdd存储在磁盘,除此之外rdd还有一个有意思的持久化方法rdd.persist,代码如下:
defpersist(newLevel: StorageLevel):this.type=
{
// TODO:Handle changes of StorageLevel
if (storageLevel!= StorageLevel.NONE&&newLevel
!= storageLevel) {//storageLevel一致性检查
throw new UnsupportedOperationException(
"Cannot change storage level of an RDD after it wasalready assigned a level")
}
sc.persistRDD(this)
// Register the RDD with the ContextCleaner for automaticGC-based cleanup
sc.cleaner.foreach(_.registerRDDForCleanup(this))//这个有必要研究一番,等再开一篇吧
storageLevel = newLevel
this
}
在此方法中首先对rdd的storageLevel进行了一致性检查,如果已经初始化了storageLevel,那么你无法通过persist方法改变其storageLevel.这里先看下StorageLevel:
classStorageLevel
private(
private var useDisk_ :Boolean,
private var useMemory_ :
Boolean,
private var useOffHeap_ :Boolean,
private var deserialized_ :Boolean,
private var replication_ :Int
= 1)
objectStorageLevel {
val NONE=new
StorageLevel(false,false,
false, false)
val DISK_ONLY=new
StorageLevel(true,false,
false, false)
val DISK_ONLY_2=new
StorageLevel(true,false,
false, false, 2)
val MEMORY_ONLY=new
StorageLevel(false,true,
false, true)
val MEMORY_ONLY_2=new
StorageLevel(false,true,
false, true, 2)
val MEMORY_ONLY_SER=new
StorageLevel(false,true,
false, false)
val MEMORY_ONLY_SER_2=new
StorageLevel(false,true,
false, false, 2)
val MEMORY_AND_DISK=new
StorageLevel(true,true,
false, true)
val MEMORY_AND_DISK_2=new
StorageLevel(true,true,
false, true, 2)
val MEMORY_AND_DISK_SER=new
StorageLevel(true,true,
false, false)
val MEMORY_AND_DISK_SER_2=new
StorageLevel(true,true,
false, false, 2)
val OFF_HEAP=new
StorageLevel(false,false,
true, false)
…
}
我很好奇DISK_ONLY和checkpoint有什么区别。
在persist方法中,调用了sc.persistRDD(this),这是sparkContext的一个方法:
private[spark] def persistRDD(rdd: RDD[_]) { persistentRdds(rdd.id) = rdd // private[spark] val persistentRdds = new TimeStampedWeakValueHashMap[Int, RDD[_]] }
其实就是将(rdd.id,rdd)放到了一个TimeStampedWeakValueHashMap中,并没有做实质性的存储的动作,也就是说实质性的存储方法在其他的地方,我们得去看rdd参加计算的时候,程序是通过什么方法获取到rdd的,就可以找到这段代码。由于涉及到任务调度系统,这段代码的调用栈十分冗长,以rdd.count为例:
Rdd.count->sparkContex.runjob->dagScheduler.runjob->dagScheduler.submitjob-> dagScheduler.receive-> dagScheduler.handleJobSubmitted->
dagScheduler .submitStage-> dagScheduler.submitMissingTasks--à taskSchedulerImpl.submitTasks->schedulableBuilder.addTaskSetManager->…task.run->rdd. iterator-> CacheManager.getorcompute->blockManager.put-> blockManager.doput,部分代码如下:
if(level.useMemory) {
// Save it just to memory first, even if it also hasuseDisk set to true; we will
// drop it to disk later if thememory store can't hold it.
val res= datamatch
{
case IteratorValues(iterator)=>
memoryStore.putValues(blockId,iterator,
level,
true)
case ArrayBufferValues(array)=>
memoryStore.putValues(blockId,array,
level,
true)
case ByteBufferValues(bytes)=>
bytes.rewind()
memoryStore.putBytes(blockId,bytes,
level)
}
以上是level.useMemory,调用的方法栈memoryStore.putValues->memoryStore. tryToPut,如下:
实际上的持久化的操作就在tryput之中,需要细读,今天太累了,看了半天有几个点懂,休息下,下次接着来:
本文深入探讨了Spark中RDD的persist方法,详细解释了如何通过不同的StorageLevel配置来实现内存或磁盘的数据持久化,以及persist方法的具体实现流程。
776

被折叠的 条评论
为什么被折叠?



