一、 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无参构造方法(默认存储只存在内存中),源码如下:

spark java 写入redis_java


2)存储级别

  默认的存储级别都是仅在内存存储一份,而Spark的存储级别还有好多种,具体参考objectStorageLevel.scala

spark java 写入redis_jvm_02

持久化级别

说明

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()方法释放缓存。