RDD通过persist方法或cache方法可以将前面的计算结果缓存,默认情况下 persist() 会把数据以序列化的形式缓存在 JVM 的堆空间中。 但是并不是这两个方法被调用时立即缓存,而是触发后面的action时,该RDD的计算结果将会被缓存在计算节点的内存中,并供后面重用。

示例如下:

def main(args: Array[String]): Unit = {
val sc: SparkContext = new SparkContext(new SparkConf().
setMaster("local[*]").setAppName("spark")) val raw: RDD[String] = sc.makeRDD(Array("hello"))
val current: RDD[String] = raw.map(_.toString + System.currentTimeMillis())
//current.persist()
current.collect().foreach(println)
current.collect().foreach(println)
current.collect().foreach(println)
}

如果不加persist方法,执行结果如下:

hello1582190762213

hello1582190762463

hello1582190762526

加了persist方法之后,执行结果变为:

hello1582190869308

hello1582190869308

hello1582190869308

可见:current这个rdd的计算结果被缓存起来了 ,下游的rdd直接从缓存拿数据并进行运算。rdd及其rdd上游的计算过程被省略了,从而加快了计算过程。

存储级别:

object StorageLevel {
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(true, true, true, false, 1)
class StorageLevel private(
private var _useDisk: Boolean,
private var _useMemory: Boolean,
private var _useOffHeap: Boolean,
private var _deserialized: Boolean,
private var _replication: Int = 1)

堆外内存:区别于JVM内存。这一块内存不受JVM的GC回收机制的影响,而是直接向操作系统申请并自主管理的一块内存空间。为什么需要这块内存:JVM中的内存由于受到GC的影响,如果没有用完可能迟迟得不到释放,这时候如果再加入数据,就可能导致OOM问题。而如果由自己来管理内存,可以更及时地释放内存。

默认存储级别为MEMORY_ONLY:

检查点

如图所示:

依赖链过长,会导致有大量的血统信息要被记录;

而且在进行数据恢复的时候,要重新从头开始计算,比较耗时;

因此引入了检查点:

血统信息会从检查点开始记录;

重新计算时,把检查点的数据作为元数据开始计算;

相当于是检查点之前的RDD链条被掐断,检查点作为新的RDD链条头。

示例代码如下:

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf()
.setAppName("wordcount").setMaster("local[*]") val sc: SparkContext = new SparkContext(conf)
sc.setCheckpointDir("cp") val lines: RDD[String] = sc.parallelize(Array(("hello,spark"),("hello,scala"),("hello,world"))) val words: RDD[String] = lines.flatMap(_.split(" ")) val wordToOne: RDD[(String, Int)] = words.map((_,1))
//wordToOne之前的血缘关系,会被检查点替代。
//wordToOne.checkpoint() val wordToSum: RDD[(String, Int)] = wordToOne.reduceByKey(_+_) wordToSum.collect() println(wordToSum.toDebugString) }

不加checkpoint的打印结果:

(8) ShuffledRDD[3] at reduceByKey at checkPoint.scala:21 []
 +-(8) MapPartitionsRDD[2] at map at checkPoint.scala:17 []
    |  MapPartitionsRDD[1] at flatMap at checkPoint.scala:15 []
    |  ParallelCollectionRDD[0] at parallelize at checkPoint.scala:13 []

从头开始记录;

加了checkpoint之后的打印结果:

(8) ShuffledRDD[3] at reduceByKey at checkPoint.scala:21 []
 +-(8) MapPartitionsRDD[2] at map at checkPoint.scala:17 []
    |  ReliableCheckpointRDD[4] at collect at checkPoint.scala:23 []

检查点所在RDD之前的RDD的血缘信息被检查点信息所替代。

接下来考察检查点之前的RDD会不会被重复计算:

def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf()
.setAppName("wordcount").setMaster("local[*]") val sc: SparkContext = new SparkContext(conf)
sc.setCheckpointDir("cp") val lines: RDD[String] = sc.parallelize(Array(System.currentTimeMillis().toString)) val words: RDD[String] = lines.flatMap(_.split(" ")) val wordToOne: RDD[(String, Int)] = words.map((_,1))
//wordToOne之前的血缘关系,会被检查点替代。
wordToOne.checkpoint() val wordToSum: RDD[(String, Int)] = wordToOne.reduceByKey(_+_) wordToSum.collect().foreach(println)
wordToSum.collect().foreach(println)
wordToSum.collect().foreach(println) }

打印结果如下:

(1582193859704,1)

(1582193859704,1)

(1582193859704,1)

证明检查点之间的RDD没有被重复计算。

RDD(八)——缓存与检查点的更多相关文章

  1. Spark RDD概念学习系列之RDD的缓存(八)

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

  2. sparkRDD:第4节 RDD的依赖关系;第5节 RDD的缓存机制;第6节 DAG的生成

    4.      RDD的依赖关系 6.1      RDD的依赖 RDD和它依赖的父RDD的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency ...

  3. RDD的缓存

    RDD的缓存/持久化 缓存解决的问题 缓存解决什么问题?-解决的是热点数据频繁访问的效率问题 在Spark开发中某些RDD的计算或转换可能会比较耗费时间, 如果这些RDD后续还会频繁的被使用到,那么可 ...

  4. Redis系列(八)--缓存穿透、雪崩、更新策略

    1.缓存更新策略 1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy 2.超时剔除,过期时间expire,对于一些用户可以容忍延时更新的数据,例如文章简介内容改了几个字 3.主 ...

  5. 关于redis的几件小事(八)缓存与数据库双写时的数据一致性

    1.Cache aside pattern 这是最经典的 缓存+数据库 读写模式,操作如下: ①读的时候,先读缓存,缓存没有就读数据库,然后将取出的数据放到缓存,同时返回请求响应. ②更新的时候,先删 ...

  6. HTML5入门八---缓存控件元素的值

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  7. Spark RDD详解 | RDD特性、lineage、缓存、checkpoint、依赖关系

    RDD(Resilient Distributed Datasets)弹性的分布式数据集,又称Spark core,它代表一个只读的.不可变.可分区,里面的元素可分布式并行计算的数据集. RDD是一个 ...

  8. Spark核心RDD、什么是RDD、RDD的属性、创建RDD、RDD的依赖以及缓存、

    1:什么是Spark的RDD??? RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行 ...

  9. RDD缓存

    RDD的缓存 Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或缓存数据集.当持久化某个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍生出的RDD进行的其他 ...

随机推荐

  1. 51nod 1421:最大MOD值

    1421 最大MOD值 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 有一个a数组,里面有n个整数.现在要从中找到两个数字(可以 ...

  2. [APIO2018]铁人两项(圆方树)

    过了14个月再重新看这题,发现圆方树从来就没有写过.然后写了这题发现自己APIO2018打铁的原因竟然是没开long long,将树的部分的O(n)写挂了(爆int),毕竟去年APIO时我啥都不会,连 ...

  3. [C/C++]'fopen': This function or variable may be unsafe

    这个错误也算比较常见吧,当然这个与代码无关,是编译器的问题,主要是VS中出现的,因为微软方面认为fopen函数是不安全的,于是自己搞了一套fopen_s的函数来代替,用前面一个的话编译器是会出错的,所 ...

  4. C++多态性与虚函数

    派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员“获得新生”.面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机 ...

  5. Python Scrapy的QQ音乐爬虫 音乐下载、爬取歌曲信息、歌词、精彩评论

    QQ音乐爬虫(with scrapy)/QQ Music Spider UPDATE 2019.12.23 已实现对QQ音乐文件的下载,出于版权考虑,不对此部分代码进行公开.此项目仅作为学习交流使用, ...

  6. 随机森林RF

    bagging 随机森林顾名思义,是用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的.在得到森林之后,当有一个新的输 入样本进入的时候,就让森林中的每一棵决 ...

  7. 动态改变tableHeaderView的显示隐藏及高度

    改变tableHeaderView的高度: UIView *headerView = _tableView.tableHeaderView; headerView.height = 10; 当设置高度 ...

  8. (转)ERROR : The processing instruction target matching "[xX][mM][lL]" is not allowed.

    现象:ERROR   : The processing instruction target matching "[xX][mM][lL]" is not allowed. 异常解 ...

  9. 运用Access学习数据库的三大范式

    第一范式(1NF):强调的是列的原子性,即“列不能够再分成其他几列”,同一列中不能有多个值. 例子:业余爱好编码表+员工编码表 当员工杨来的业余爱好有多个时,此时的数据库设计不满足第一范式,可进行如下 ...

  10. uniapp 初始化项目

    const baseUrl = 'http://10.92.1.17:6601/videoapi/'; //const baseUrl = '/videoapi/'; //对于 GET 方法,会将数据 ...