spark的持久化
- cache
- persisit
- checkpoint
以上算子都可以将RDD持久化,持久化的单位是partition。cache和persist都是懒执行的。必须有一个action类算子触发执行。checkpoint算子不仅能将RDD持久化到磁盘,还能切断RDD之间的依赖关系。
1. cache
默认将RDD的数据持久化到内存中。cache是懒执行。
注意:cache () = persist()
=persist(StorageLevel.Memory_Only)
2. persist
可以指定持久化的级别。最常用的是MEMORY_ONLY和MEMORY_AND_DISK。”_2”表示有副本数。
2.5. cache和persist注意事项
cache和persist注意事项:
- cache和persist都是懒执行,必须有一个action类算子触发执行。
- cache和persist算子的返回值可以赋值给一个变量,在其他job中直接使用这个变量就是使用持久化的数据了。持久化的单位是partition。
- cache和persist算子后不能立即紧跟action算子。
错误:rdd.cache().count() 返回的不是持久化的RDD,而是一个数值了
3.checkpoint
checkpoint将RDD持久化到磁盘,还可以切断RDD之间的依赖关系。
checkpoint 的执行原理:
- 当RDD的job执行完毕后,会从finalRDD从后往前回溯。
- 当回溯到某一个RDD调用了checkpoint方法,会对当前的RDD做一个标记。
- Spark框架会自动启动一个新的job,重新计算这个RDD的数据,将数据持久化到HDFS上。
优化:对RDD执行checkpoint之前,最好对这个RDD先执行cache,这样新启动的job只需要将内存中的数据拷贝到HDFS上就可以,省去了重新计算这一步。
4. 源码解读
RDD.scala
/** 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()
StorageLevel.scala
class StorageLevel private(
private var _useDisk: Boolean, //是否使用磁盘
private var _useMemory: Boolean, //是否使用内存
private var _useOffHeap: Boolean, //是否使用堆外内存(主要指tachyon)
private var _deserialized: Boolean, //是否不序列化
private var _replication: Int = 1) //副本数量
extends Externalizable {
//-----------------------
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(false, false, true, false)
注意:
- MEMORY_ONLY :仅当内存能够装下RDD的数据时,才进行持久化到内存
- MEMORY_AND_DISK :当内存不够时,剩下RDD的数据持久化到磁盘
- eg: 500M内存,RDD的数据为2G,若为MEMORY_ONLY持久化方式,则因为内存装不下,RDD其所有数据都不会持久化;若为MEMORY_AND_DISK,则会持久化500M的RDD数据到内存,剩下1.5G存储到磁盘
5. Demo
CacheDemo.scala
package com.qiuyang.scala
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkContext, SparkConf}
/**
* Created by qiuyang on 2018/11/30.
*
* 持久化算子
* cache/persist/checkpoint,均为懒执行算子,需要Action算子触发执行
* 三个持久化算子,持久化的单位都是partition
* 1.cache: 默认将RDD中的数据存储在内存中
* 2.persist(): 可选择存储方式,persist(StorageLevel.MEMORY_ONLY)=cache()=persist()
* *cache和persist注意:
* >cache和persist都是懒执行,需要Actio算子触发执行
* >对一个RDD cache或persist之后可以赋值给一个变量,下次直接使用这个变量就是使用持久化的RDD
* >如果赋值给一个变量,那么cache和persist之后不能紧跟Action算子
* 3.checkponit: 会封装job执行
*
*/
object CacheDemo {
def main(args: Array[String]) {
val conf: SparkConf = new SparkConf()
conf.setAppName("CacheDemo").setMaster("local")
val sc: SparkContext = new SparkContext(conf)
var lines: RDD[String] = sc.textFile("/Users/qiuyang/githublib/qiuyang-spark-scala/src/word")
// val count1: Long = lines.filter(_.equals("hello scala")).count()
// val count2: Long = lines.filter(!_.equals("hello scala")).count()
// println("number of \"hello scala\":"+count1)
// println("others:"+count2)
val start: Long = System.currentTimeMillis()
val count1: Long = lines.count()
val end: Long = System.currentTimeMillis()
println("count1 = "+count1+", time1 = "+(end-start)+"ms")
lines = lines.cache()
val start2: Long = System.currentTimeMillis()
val count2: Long = lines.count()
val end2: Long = System.currentTimeMillis()
println("count2 = "+count2+", time2 = "+(end2-start2)+"ms")
sc.stop()
}
}
CheckPonitDemo.scala
package com.qiuyang.scala
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* Created by qiuyang on 2018/11/30.
* CheckPoint持久化--会封装一个job
* 特点:
* 1.将数据存储再磁盘中,一定要先用sc.setCheckpointDir指定存储路径
* 2.切断了与前面RDD的联系
* 3.CheckPoint与persist(StorageLevel.DISK_ONLY)的区别?=>Application运行完后,后者就没了,被回收了,而CheckPoint存储的数据还在
* 4.某些特定场景,必须用CheckPoint
* 5.CheckPoint是懒加载,且它会再job执行完成之后,spark自动封装job去执行
*/
object CheckPonitDemo {
def main(args: Array[String]) {
val sc: SparkContext = new SparkContext(new SparkConf().setMaster("local").setAppName("checkpointdemo"))
//设置checkpoint存储数据的位置,可指定为hdfs上的位置,此处指定本地,会自动创建文件夹
sc.setCheckpointDir("./checkpoint")
val lines: RDD[String] = sc.textFile("/Users/qiuyang/githublib/qiuyang-spark-scala/src/word")
lines.checkpoint()
println(lines.count())
sc.stop()
}
}