目录
一、RDD持久化原理
二、RDD缓存
三、RDD持久化策略
四、checkpoint检查点机制
五、缓存和检查点区别
5.1cache和persist⽐较
5.3什么时候使⽤cache或checkpoint
一、RDD持久化原理
Spark非常重要的一个功能特性就是可以将RDD持久化在内存中。当对RDD执行持久化操作时,每个节点都会将自己操作的RDD的partition持久化到内存中,并且在之后对
该RDD的反复使用中,直接使用内存缓存的partition。这样的话,对于针对一个RDD反复执行多个操作的场景,就只要对RDD计算一次即可,后面直接使用该RDD,而不需要反复计算多次该RDD。
巧妙使用RDD持久化,甚至在某些场景下,可以将spark应用程序的性能提升10倍。对于迭代式算法和快速交互式应用来说,RDD持久化,是非常重要的。
要持久化一个RDD,只要调用其cache()或者persist()方法即可。在该RDD第一次被计算出来时,就会直接缓存在每个节点中。而且Spark的持久化机制还是自动容错的,如果持久化的RDD的任何partition丢失了,那么Spark会自动通过其源RDD,使用transformation操作重新计算该partition。
cache()和persist()的区别在于,cache()是persist()的一种简化方式,cache()的底层就是调用的persist()的无参版本,同时就是调用persist(MEMORY_ONLY),将数据持久化到内存中。如果需要从内存中清楚缓存,那么可以使用unpersist()方法。
Spark自己也会在shuffle操作时,进行数据的持久化,比如写入磁盘,主要是为了在节点失败时,避免需要重新计算整个过程。
![](https://i-blog.csdnimg.cn/blog_migrate/600d538267617f7b7755eb9ae5d2c582.png)
二、RDD缓存
Spark速度⾮常快的原因之⼀,就是在不同操作中可以在内存中持久化或缓存个数据集。当持久化某个
RDD
后,每 ⼀个节点都将把计算的分⽚结果保存在内存中,并在对此RDD
或衍⽣出的
RDD
进⾏的其他动作中重⽤。这使得后续的动作变得更加迅速。RDD
相关的持久化和缓存,是
Spark
最重要的特征之⼀。可以说,缓存是
Spark
构建迭代式算法和快速交互式查询的关键。如果⼀个有持久化数据的节点发⽣故障,Spark
会在需要⽤到缓存的数据时重算丢失的数据分区。如果 希望节点故障的情况不会拖累我们的执⾏速度,也可以把数据备份到多个节点上。
/**
RDD通过persist⽅法或cache⽅法可以将前⾯的计算结果缓存,但是并不是这两个⽅法被调⽤时⽴即缓存,⽽是触发
后⾯的action时,该RDD将会被缓存在计算节点的内存中,并供后⾯重⽤
*/
/** 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.MEMORY_ONLY (默认就是存到内存中)
三、RDD持久化策略
RDD持久化是可以手动选择不同的策略的。比如可以将RDD持久化在内存中、持久化到磁盘上、使用序列化的方式持久化,多持久化的数据进行多路复用。 只要在调用persist()时传入对应的StorageLevel即可。
持久化级别等级源码查看
含义解释
注:MEMORY_AND_DISK
先存储到内存中内存存储满了在存到磁盘
MEMORY_ONLY
内存只能存储内存⼤⼩的数据
,
超出的部分将不会再存储
因为内存中只存了⼀部分
,
少了⼀部分数据
,
这部分数据被加载时它会重新计算
堆外内存
:
堆外内存是相对于对内内存⽽⾔
,
堆内内存是由
JVM
管理的
,
在平时
java
中创建对象都处于堆内内存
,
并且它 是遵守JVM
的内存管理规则
(
GC
垃圾回收机制
),
那么堆外内存就是存在于
JVM
管控之外的⼀块内存
,
它不受
JVM
的管控约 束缓存容易丢失
,
或者存储在内存的数据由于内存存储不⾜可能会被删掉
.
RDD
的缓存容错机制保证了即缓存丢失也能保 证正确的的计算出内容
,
通过
RDD
的⼀些列转换
,
丢失的数据会被重算
,
由于
RDD
的各个
Partition
是独⽴存在
,
因此只需 要计算丢失部分的数据即可
,
并不需要计算全部的
Partition
四、checkpoint检查点机制
Spark中对于数据的保存除了持久化操作之外,还提供了⼀种检查点的机制,检查点(本质是通过将
RDD
写⼊
Disk 做检查点)是为了通过lineage
做容错的辅助,
lineage
过⻓会造成容错成本过⾼,这样就不如在中间阶段做检查点容错,如果之后有节点出现问题⽽丢失分区,从做检查点的RDD
开始重做
Lineage
,就会减少开销。检查点通过将数据写⼊到HDFS
⽂件系统实现了
RDD
的检查点功能。
使⽤
:
/*
检查点,类似于快照,chekpoint的作⽤就是将DAG中⽐较重要的数据做⼀个检查点,将结果存储到⼀个⾼可⽤的地
⽅
*/
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("SparkDemo").setMaster("local")
val sc = new SparkContext(conf)
sc.setCheckpointDir("hdfs://hadoop01:8020/ck")
val rdd = sc.textFile("hdfs://hadoop01:8020/word.txt").flatMap(_.split("
")).map((_,1)).reduceByKey(_+_)
//检查点的触发⼀定要使⽤个action算⼦
rdd.checkpoint()
rdd.saveAsTextFile("hdfs://hadoop01:8020/out10")
println(rdd.getCheckpointFile) //查看存储的位置
/**
查看是否可以设置检查点 rdd.isCheckpointed 这个⽅法在shell中可以使⽤ 但是代码中不好⽤
*/
}
五、缓存和检查点区别
缓存把 RDD
计算出来然后放在内存中,但是
RDD
的依赖链(相当于数据库中的
redo
⽇志), 也不能丢掉, 当某个点某个 executor
宕了,上⾯
cache
的
RDD
就会丢掉, 需要通过 依赖链重放计算出来, 不同的是, checkpoint 是把 RDD
保存在
HDFS
中, 是多副本可靠存储,所以依赖链就可以丢掉了,就斩断了依赖链, 是通过复制实现的⾼容错。
读取数据是⾃动的但是写数据需要⼿动
![](https://i-blog.csdnimg.cn/blog_migrate/e773cbeb8e5852c67f72b6ad8d0bdf5d.png)
注:
当使⽤了
checkpoint
后,数据被保存到
HDFS
,
此
RDD
的依赖关系也会丢掉
,因为数据已经持久化到
HDFS,
所以不需要重新计算,
⽆论是
cache
或
checkpoint
缓存了数据
,
若数据丢失是⾃动恢复的
,checkpoint
的数据需要⼿动清除⽽cache
的数据是⾃动清除的
(
任务结束
)
cache
是把 RDD
保存在
内存中,依赖关系不可以丢
checkpoint 是把 RDD
保存在
HDFS中,依赖关系可以丢
5.1cache和persist⽐较
cache源码中调⽤的是
persist,persist
更加底层的持久化
,cache
默认持久化等级是内存且不能修改
,
⽽
persist
是可以 修改持久化等级,cache
和
persist
的使⽤是有规则的必须在
transformation
或者
textfile
等创建⼀个
rdd
之后,直接连续调⽤cache()
或者
persist()
才可以,如果先创建⼀个
rdd,
再单独另起⼀⾏执⾏
cache()
或者
persist()
,是没有⽤的,⽽且会报错,
5.3什么时候使⽤cache或checkpoint
1.
某步骤计算特别耗时
2.
计算链条特别⻓
3.
发⽣
shuffle
之后
建议使⽤
cache
或是
persist
模式因为
,
不需要创建存储位置
,
并且默认存储到内存中计算速度快
,
⽽
checkpoint
需要⼿ 动创建存储位置和⼿动删除数据.
若数据量⾮常庞⼤建议改⽤
chechpoint.
psps:注意cache时内存不足OOM(爆了)!!!