一、 RDD Cache缓存
RDD通过Cache或者Persist方法将前面的计算结果缓存,默认情况下会把数据以序列化的形式缓存在JVM的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的action算子时,该RDD将会被缓存在计算节点的内存中,并供后面重用。
1)RDD Cache缓存代码实现
public class CacheDemo {
public static void main(String[] args) throws InterruptedException {
//1、创建配置对象,并创建sparkContext上下文计算对象
JavaSparkContext sc = new JavaSparkContext(new SparkConf().setMaster("local[*]").setAppName("sparkCore"));
//2、逻辑处理
//读取数据
JavaRDD<String> lineRDD = sc.textFile("F:/Desktop/data.txt");
//按照空格将数据切分
JavaRDD<String> wordRDD = lineRDD.flatMap(v -> Arrays.asList(v.split(" ")).iterator());
//转换数据结构word->(word,1)
JavaPairRDD<String, Integer> pairRDD = wordRDD.mapToPair(v -> new Tuple2<>(v, 1));
System.out.println("=============");
//打印血缘关系
System.out.println(pairRDD.toDebugString());
/*
添加缓存方法有两个:cache和persist(底层方法,可以修改缓存级别)
*/
pairRDD.cache();
//pairRDD.persist(StorageLevel.MEMORY_ONLY);
//任务1
pairRDD.collect().forEach(System.out::println);
//打印血缘关系
System.out.println(pairRDD.toDebugString());
//任务2
pairRDD.collect().forEach(System.out::println);
//释放缓存
pairRDD.unpersist();
//线程睡眠,查看4040端口
Thread.sleep(Long.MAX_VALUE);
//3、关闭资源
sc.close();
}
}
通过查看RDD源码可以看出cache底层调用了persist无参构造方法(默认存储只存在内存中),源码如下:
2)存储级别
默认的存储级别都是仅在内存存储一份,而Spark的存储级别还有好多种,具体参考objectStorageLevel.scala
持久化级别 | 说明 |
MORY_ONLY(默认) | 将 RDD 以非序列化的 Java 对象存储在 JVM 中。 如果没有足够的内存存储 RDD,则某些分区将不会被缓存,每次需要时都会重新计算。 |
MORY_AND_DISK(开发中常用) | 将 RDD 以非序列化的 Java 对象存储在 JVM 中。如果数据在内存中放不下,则溢写到磁盘上.需要时则会从磁盘上读取 |
MEMORY_ONLY_SER (Java and Scala) | 将 RDD 以序列化的 Java 对象(每个分区一个字节数组)的方式存储.这通常比非序列化对象(deserialized objects)更具空间效率,特别是在使用快速序列化的情况下,但是这种方式读取数据会消耗更多的 CPU |
MEMORY_AND_DISK_SER (Java and Scala) | 与 MEMORY_ONLY_SER 类似,但如果数据在内存中放不下,则溢写到磁盘上,而不是每次需要重新计算它们 |
DISK_ONLY | 将 RDD 分区存储在磁盘上 |
MEMORY_ONLY_2, MEMORY_AND_DISK_2 等 | 与上面的储存级别相同,只不过将持久化数据存为两份,备份每个分区存储在两个集群节点上 |
二、RDD CheckPoint检查点
1)检查点
通过将RDD中间结果写入磁盘。(从头开始执行,另起一个job,切断血缘关系)
2)为什么要做检查点?
由于血缘依赖过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销。
3)检查点存储路径
Checkpoint的数据通常是存储在HDFS等容错、高可用的文件系统。
4)检查点数据存储格式
二进制的文件
5)检查点切断血缘
在Checkpoint的过程中,该RDD的所有依赖于父RDD中的信息将全部被移除。
6)检查点触发时间
对RDD进行Checkpoint操作并不会马上被执行,必须执行Action操作才能触发。但是检查点为了数据安全,会从血缘关系的最开始执行一遍。
7)设置检查点步骤
1)设置检查点数据存储路径:sc.setCheckpointDir("F:/Desktop/checkpoint")
2)调用检查点方法:wordToOneRdd.checkpoint()
8)CheckPoint 检查点代码实现
public class CheckPointDemo{
public static void main(String[] args) throws InterruptedException {
//1、创建配置对象,并创建sparkContext上下文计算对象
JavaSparkContext sc = new JavaSparkContext(new SparkConf().setMaster("local[*]").setAppName("sparkCore"));
//2、逻辑处理
//设置检查点一定要设置检查点的目录
sc.setCheckpointDir("F:/Desktop/checkpoint");
//读取数据
JavaRDD<String> lineRDD = sc.textFile("F:/Desktop/data.txt");
//按照空格将数据切分
JavaRDD<String> wordRDD = lineRDD.flatMap(v -> Arrays.asList(v.split(" ")).iterator());
//转换数据结构word->(word,1)
JavaPairRDD<String, Integer> pairRDD = wordRDD.mapToPair(v -> new Tuple2<>(v, 1));
//检查点前打印血缘关系
System.out.println(pairRDD.toDebugString());
//公司开发,做检查点之间先做缓存,检查点先进缓存,避免从头计算
pairRDD.cache();
//pairRDD.persist(StorageLevel.MEMORY_AND_DISK());
//添加检查点
pairRDD.checkpoint();
//任务1
pairRDD.collect().forEach(System.out::println);
//检查点后打印血缘关系
System.out.println(pairRDD.toDebugString());
//任务2
pairRDD.collect().forEach(System.out::println);
//任务3
pairRDD.collect().forEach(System.out::println);
//线程睡眠,查看4040端口,可以查看有向无环图,血缘关系被切断
Thread.sleep(Long.MAX_VALUE);
//3、关闭资源
sc.close();
}
}
三、缓存和检查点的区别
(1)Cache缓存只是将数据保存起来,不切断血缘依赖。Checkpoint检查点切断血缘依赖。
(2)Cache缓存的数据通常存储在磁盘、内存等地方,可靠性低。Checkpoint的数据通常存储在HDFS等容错、高可用的文件系统,可靠性高。
(3)开发中常对checkpoint()的RDD使用Cache缓存,这样checkpoint的job只需从Cache缓存中读取数据即可,否则需要再从头计算一次RDD。
(4)如果使用完了缓存,可以通过unpersist()方法释放缓存。