RDD的缓存

RDD的缓存和RDD的checkpoint的区别

缓存是在计算结束后,直接将计算结果通过用户定义的存储级别(存储级别定义了缓存存储的介质,现在支持内存、本地文件系统和Tachyon)写入不同的介质。

而检查点不同,它是在计算完成后,重新建立一个Job来计算。

为了避免重复计算,推荐先将RDD缓存,这样就能保证检查点的操作可以快速完成。

  RDD的缓存能够在第一次计算完成后,将计算结果保存到内存、本地文件系统或者Tachyon(分布式内存文件系统)中。通过缓存,Spark避免了RDD上的重复计算,能够极大地提升计算速度。

  Spark速度非常快的原因之一,就是在不同操作中在内存中持久化(或缓存)一个数据集。当持久化一个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此数据集(或者衍生出的数据集)进行的其他动作(action)中重用。这使得后续的动作变得更加迅速(通常快10倍)。RDD相关的持久化和缓存,是Spark最重要的特征之一。可以说,缓存是Spark构建迭代式算法和快速交互式查询的关键。

  通过persist()或cache()方法可以标记一个要被持久化的RDD,一旦首次被触发,该RDD将会被保留在计算节点的内存中并重用。实际上,cache()是使用persist()的快捷方法,它们的实现如下:

/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
def persist(): this.type = persist(StorageLevel.MEMORY_ONLY)
/** Persist this RDD with the default storage level (`MEMORY_ONLY`). */
def cache(): this.type = persist()

图1中,假设首先进行了RDD0→RDD1→RDD2的计算作业,那么计算结束时,RDD1就已经缓存在系统中了。在进行RDD0→RDD1→RDD3的计算作业时,由于RDD1已经缓存在系统中,因此RDD0→RDD1的转换不会重复进行,计算作业只须进行RDD1→RDD3的计算就可以了,因此计算速度可以得到很大提升。

              图1  RDD缓存过的Partition可以加快下一次的计算速度

缓存有可能丢失,或者存储于内存的数据由于内存不足而被删除。RDD的缓存的容错机制保证了即使缓存丢失也能保证计算的正确执行。通过基于RDD的一系列的转换,丢失的数据会被重算。RDD的各个Partition是相对独立的,因此只需要计算丢失的部分即可,并不需要重算全部Partition。

  RDD的缓存的处理

  如果存储级别不是NONE,那么先检查是否有缓存;没有缓存则要进行计算。什么是存储级别?从用户的角度来看就是缓存保存到不同的存储位置,比如内存、硬盘、Tachyon;还有缓存的数据是否需要序列化等。
  cacheManager对Storage模块进行了封装,使得RDD可以更加简单地从Storage模块读取或者写入数据。RDD的每个Partition对应Storage模块的一个Block,只不过Block是Partition经过处理后的数据。在系统实现的层面上,可以认为Partition和Block是一一对应的。cacheManager会通过getOrCompute来判断当前的RDD是否需要进行计算。

  首先,cacheManager会通过RDD的ID和当前计算的Partition的ID向Storage模块的BlockManager发起查询请求,如果能够获得Block的信息,会直接返回Block的信息。否则,代表该RDD是需要计算的。这个RDD以前可能计算过并且被存储到了内存中,但是后来由于内存紧张,这部分内存被清理了。在计算结束后,计算结果会根据用户定义的存储级别,写入BlockManager中。这样,下次就可以不经过计算而直接读取该RDD的计算结果了。

核心实现逻辑如下:

def getOrCompute[T](
    rdd: RDD[T],
    partition: Partition,

    context: TaskContext,
    storageLevel: StorageLevel): Iterator[T] = {
  //获取RDD的BlockId
  val key = RDDBlockId(rdd.id, partition.index)
  logDebug(s"Looking for partition $key")

  blockManager.get(key) match { //向BlockManager查询是否有缓存

case Some(blockResult) => //缓存命中
  //更新统计信息,将缓存作为结果返回
  context.taskMetrics.inputMetrics = Some(blockResult.inputMetrics)

  new InterruptibleIterator(context, blockResult.data.asInstanceOf[Iterator[T]])
case None => //没有缓存命中,需要计算
  //判断当前是否有线程在处理当前的Partition,如果有那么等待它结束后,直接从Block
  // Manager中读取处理结果如果没有线程在计算,那么storedValues就是None,否则

  //就是计算的结果
  val storedValues = acquireLockForPartition[T](key)
  if (storedValues.isDefined) { //已经被其他线程处理了,直接返回结果

    return new InterruptibleIterator[T](context, storedValues.get)
  }

//需要计算
try {
//如果被checkpoint过,那么读取checkpoint的数据;否则调用rdd的compute()开始计算

val computedValues = rdd.computeOrReadCheckpoint(partition,context)
// Task是在Driver端执行的话就不需要缓存结果,这个主要是为了first()或者take()
//这种仅仅有一个执行阶段的任务的快速执行。这类任务由于没有Shuffle阶段,直接运行

//在Driver端可能会更省时间

if (context.isRunningLocally) {
return computedValues

}

//将计算结果写入到BlockManager
val updatedBlocks = new ArrayBuffer[(BlockId, BlockStatus)]
val cachedValues =
  putInBlockManager(key, computedValues, storageLevel, updatedBlocks)

//更新任务的统计信息

val metrics = context.taskMetrics
val lastUpdatedBlocks = metrics.updatedBlocks.getOrElse(
  Seq[(BlockId, BlockStatus)]())
metrics.updatedBlocks = Some(lastUpdatedBlocks ++ updatedBlocks.toSeq)
new InterruptibleIterator(context, cachedValues)
} finally {
loading.synchronized {
loading.remove(key)

//如果有其他的线程在等待该Partition的处理结果,那么通知它们计算已经完成,结果已

//经存到BlockManager中(注意前面那类不会写入BlockManager的本地任务)

// loading.notifyAll()
      }
    }
  }
}

Spark RDD概念学习系列之RDD的缓存(八)的更多相关文章

  1. Spark RDD概念学习系列之RDD的checkpoint(九)

     RDD的检查点 首先,要清楚.为什么spark要引入检查点机制?引入RDD的检查点?  答:如果缓存丢失了,则需要重新计算.如果计算特别复杂或者计算耗时特别多,那么缓存丢失对于整个Job的影响是不容 ...

  2. Spark RDD概念学习系列之RDD是什么?(四)

       RDD是什么? 通俗地理解,RDD可以被抽象地理解为一个大的数组(Array),但是这个数组是分布在集群上的.详细见  Spark的数据存储 Spark的核心数据模型是RDD,但RDD是个抽象类 ...

  3. Spark RDD概念学习系列之RDD的转换(十)

    RDD的转换 Spark会根据用户提交的计算逻辑中的RDD的转换和动作来生成RDD之间的依赖关系,同时这个计算链也就生成了逻辑上的DAG.接下来以“Word Count”为例,详细描述这个DAG生成的 ...

  4. Spark RDD概念学习系列之RDD的操作(七)

    RDD的操作 RDD支持两种操作:转换和动作. 1)转换,即从现有的数据集创建一个新的数据集. 2)动作,即在数据集上进行计算后,返回一个值给Driver程序. 例如,map就是一种转换,它将数据集每 ...

  5. Spark RDD概念学习系列之RDD的依赖关系(宽依赖和窄依赖)(三)

    RDD的依赖关系?   RDD和它依赖的parent RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency). 1)窄依赖指的是每 ...

  6. Spark RDD概念学习系列之RDD的缺点(二)

        RDD的缺点? RDD是Spark最基本也是最根本的数据抽象,它具备像MapReduce等数据流模型的容错性,并且允许开发人员在大型集群上执行基于内存的计算. 为了有效地实现容错,(详细见ht ...

  7. Spark RDD概念学习系列之rdd的依赖关系彻底解密(十九)

    本期内容: 1.RDD依赖关系的本质内幕 2.依赖关系下的数据流视图 3.经典的RDD依赖关系解析 4.RDD依赖关系源码内幕 1.RDD依赖关系的本质内幕 由于RDD是粗粒度的操作数据集,每个Tra ...

  8. Spark RDD概念学习系列之RDD与DSM的异同分析(十三)

    RDD是一种分布式的内存抽象,下表列出了RDD与分布式共享内存(Distributed Shared Memory,DSM)的对比. 在DSM系统[1]中,应用可以向全局地址空间的任意位置进行读写操作 ...

  9. Spark RDD概念学习系列之RDD的容错机制(十七)

    RDD的容错机制 RDD实现了基于Lineage的容错机制.RDD的转换关系,构成了compute chain,可以把这个compute chain认为是RDD之间演化的Lineage.在部分计算结果 ...

随机推荐

  1. leetcode:Unique Binary Search Trees

    Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For examp ...

  2. 【转】Android Launcher研究 (一)

    这份源码是基于2.1的launcher2,以后版本虽有变化,但大概的原理一直还是保留了. 一.主要文件和类  1.Launcher.java:launcher中主要的activity. 2.DragL ...

  3. how bootstrap fit into our website design?

    在web相关技术中,HTML代表了content,structure, CSS则负责styling,决定内容是如何展示的,javascript则主要负责interactive, behaviour. ...

  4. 【笨嘴拙舌WINDOWS】GDI对象之位图

    GDI对象在windows中可以描述成为一次绘画操作时可使用的抽象工具.包括(画笔.画刷.字体.区域.调色板.位图等) GDI对象里的对象概念和在编程领域中面向对象编程的对象概念是不一样的! GDI对 ...

  5. UVa 11624 (BFS) Fire!

    也是一个走迷宫的问题,不过又有了点变化. 这里迷宫里有若干把火,而且火每秒也是向四个方向蔓延的.问人是否能走出迷宫. 我用了两遍BFS,第一遍把所有着火的格子加入队列,然后计算每个格子着火的时间. 第 ...

  6. mysql日期函数(转)

    MySQL 获得当前日期时间 函数 获得当前日期+时间(date + time)函数:now() mysql> select now(); +---------------------+ | n ...

  7. 【英语】Bingo口语笔记(51) - 相信怀疑的表达

  8. list() and tuple()

    >>> l = list('sdfsdf') >>> l ['s', 'd', 'f', 's', 'd', 'f'] >>> t = tuple ...

  9. 一天一点MySQL复习——获取数据库系统时间、变量赋值、变量比较

    一.SQL获取系统时间 mysql> select now() from dual; +---------------------+ | now() | +------------------- ...

  10. 【转】session setup failed: NT_STATUS_LOGON_FAILURE -- 不错

    原文网址:http://blog.sina.com.cn/s/blog_5cdb72780100l26f.html samba服务器出现“session setup failed: NT_STATUS ...