RDD(八)——缓存与检查点
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(八)——缓存与检查点的更多相关文章
- Spark RDD概念学习系列之RDD的缓存(八)
RDD的缓存 RDD的缓存和RDD的checkpoint的区别 缓存是在计算结束后,直接将计算结果通过用户定义的存储级别(存储级别定义了缓存存储的介质,现在支持内存.本地文件系统和Tachyon) ...
- sparkRDD:第4节 RDD的依赖关系;第5节 RDD的缓存机制;第6节 DAG的生成
4. RDD的依赖关系 6.1 RDD的依赖 RDD和它依赖的父RDD的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency ...
- RDD的缓存
RDD的缓存/持久化 缓存解决的问题 缓存解决什么问题?-解决的是热点数据频繁访问的效率问题 在Spark开发中某些RDD的计算或转换可能会比较耗费时间, 如果这些RDD后续还会频繁的被使用到,那么可 ...
- Redis系列(八)--缓存穿透、雪崩、更新策略
1.缓存更新策略 1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy 2.超时剔除,过期时间expire,对于一些用户可以容忍延时更新的数据,例如文章简介内容改了几个字 3.主 ...
- 关于redis的几件小事(八)缓存与数据库双写时的数据一致性
1.Cache aside pattern 这是最经典的 缓存+数据库 读写模式,操作如下: ①读的时候,先读缓存,缓存没有就读数据库,然后将取出的数据放到缓存,同时返回请求响应. ②更新的时候,先删 ...
- HTML5入门八---缓存控件元素的值
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Spark RDD详解 | RDD特性、lineage、缓存、checkpoint、依赖关系
RDD(Resilient Distributed Datasets)弹性的分布式数据集,又称Spark core,它代表一个只读的.不可变.可分区,里面的元素可分布式并行计算的数据集. RDD是一个 ...
- Spark核心RDD、什么是RDD、RDD的属性、创建RDD、RDD的依赖以及缓存、
1:什么是Spark的RDD??? RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行 ...
- RDD缓存
RDD的缓存 Spark速度非常快的原因之一,就是在不同操作中可以在内存中持久化或缓存数据集.当持久化某个RDD后,每一个节点都将把计算的分片结果保存在内存中,并在对此RDD或衍生出的RDD进行的其他 ...
随机推荐
- 2020/2/2 PHP代码审计之反序列化
0x00 序列化与反序列化 序列化: serialize()把对象转换为字节序列的过程称为对象的序列化 反序列化: unserialize()把字节序列恢复为对象的过程称为对象的反序列化 0x01 序 ...
- caffe + ssd网络训练过程
參考博客:https://blog.csdn.net/xiao_lxl/article/details/79106837 1获取源代码:git clone https://github.com/wei ...
- 代码review还是需要再仔细点-一次crash异常分析的总结
版本发布之后,外网新增了一些crash, 从mini dump看,的确是有异常的,619行crash了. 代码如下: 奔溃的地方如下 可以看到是Zip add的时候指针空了, 为什么呢? 结合代码,可 ...
- hook截获自定义消息
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- UVA_10603 倒水问题 隐式图搜索
这道题目是刘汝佳白书上的例题,没有LRJ在白书上提到的划归为搜索问题,还真是一时难以想到好的解法.即三个瓶子,任意的一个状态都是一个节点,最后就划归为一个搜索问题. 由于题目数据量不大,三个杯子容量都 ...
- python pandas字符串函数详解(转)
pandas字符串函数详解(转)——原文连接见文章末尾 在使用pandas框架的DataFrame的过程中,如果需要处理一些字符串的特性,例如判断某列是否包含一些关键字,某列的字符长度是否小于3等等 ...
- Ubuntu16.04编译tensorflow的C++接口
原文:https://www.bearoom.xyz/2018/09/27/ubuntu1604buildtf4cpp/ 之前有一篇介绍到在windows下利用VS2015编译tensorflow的C ...
- Java 语句while、do while、for循环、嵌套、for与while的区别、break continue(3)
for循环语句,双从for嵌套: /* for(初始化表达式:循环条件表达式:循环后的操作表达式) { 执行语句: } */ /*1,变量有自己的作用域.对于for来讲:如果将用于控制循环的增量定义在 ...
- 90.QuerySet API方法使用详解:distinct
distinct:去掉获取的数据中的重复数据,这个方法如果底层使用的数据库是mysql,那么就不能传递任何参数. (1)比如以下我们想要实现提取所有价格超过80元的图书,并且删掉那些重复的,那么可以使 ...
- Java Properties基础知识总结
在Java语言中,使用一种以.properties为扩展名的文本文件作为资源文件,该类型的文件的内容格式为类似: some_key=some_value #注释描述 还有一种是使用xml文件保存项目的 ...