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进行的其他 ...
随机推荐
- part8 详情页面动态路由以及banner布局
1.<router-link>标签 a标签就会把里面文字的颜色变掉 那我们可以换一种写法 <router-link tag='li'> //这样vue就会把这个标签渲染成li标 ...
- C++ CreateInstance("ADODB.Connection");创建接口失败的解决方法
数据库对象mssql2005sp3专业版: 一般数据引用该路径文件#import "c:\\program files\\common files\\system\\ado\\msado15 ...
- python爬取招聘网站数据
# -*- coding: utf-8 -*- # 爬虫分析 from bs4 import BeautifulSoup from lxml import etree from selenium im ...
- HTML5中的行级标签和块级标签
行级标签 1.行级标签又称为内联标签,行级标签不会单独占据一行,设置宽高无效. 2.行内内部可以容纳其他行内元素,但不可以容纳块元素.有span.strong.em.b.i.input.a.img.u ...
- codeforces 596 C. p-binary
题意:给你一个n和一个p,让你用 (2k+p)进制来表示n,找出用最少的(2k+p)来表示n. 分析:首先我们看到2k,首先下想到二进制,我们可以我们列出式子,也就是 (2x1 + p)+(2x2 + ...
- HTML超链接实例介绍
<html><head><title>第六节课</title><meta charset="UTF-8"></he ...
- String StringBuffer和StringBuilder的区别和联系
1:String,StringBuffer和StringBuilder概念 1.1:String String中使用字符串数组来存储字符串,但是是fianl来修饰的,所以String的内容不可改变. ...
- 池ThreadPoolExecutor使用简介
public static void main(String[] args) { //guava 创建线程池 //https://blog.csdn.net/chinabestchina/articl ...
- C++queue的使用
C++队列是一种容器适配器,提供了一种先进先出的数据结构. 队列(queue)模板类定义在<queue>头文件中 基本操作: 定义一个queue变量:queue<Type> q ...
- ZJNU 2342 - 夏华献要回家
(夏华献在学校也要做一次梦!) 把5的答案手动算出 会发现从学校开始,兔子的数量呈斐波那契数列(第2项开始)增长 假如现在有n盏路灯 那么睡觉的时间可以得到为 但是n有1e18大,明显使用标准数学公式 ...