Spark---持久化

Spark之持久化


文章目录

  • Spark之持久化
  • 持久化
  • RDD Cache 缓存
  • RDD Persist 缓存
  • RDD CheckPoint 检查点
  • 缓存和检查点区别
    • cache
    • persist
    • checkpoint


持久化

持久化的作用,供RDD的重复使用,针对计算耗时比较长,可以提高计算的效率,针对数据比较重要的数据保存到持久化中,数据的安全性也可以得到保障。
以WordCount为例
在map操作后可以使用reduceByKey也可以使用groupByKey
但是无论是用哪种方法,都必须从数据源从头开始
Spark---持久化_第1张图片
持久化操作后,针对数据比较重要的数据保存到持久化中
Spark---持久化_第2张图片

def main(args: Array[String]): Unit = {
    val sparkConf: SparkConf = new SparkConf().setMaster("local").setAppName("wordcount")
    val sc = new SparkContext(sparkConf)
    println("===========reduceByKey操作=============")
    val list = List("Hello Scala", "Hello Spark")
    val rdd: RDD[String] = sc.makeRDD(list)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(word =>{
    //这里map操作设置了打印操作,来方便区别
      println("@@@@@@@@@@")
      (word,1)
    })
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_ + _)
    reduceRDD.collect().foreach(println)
    println("===========groupByKey操作=============")
    val groupRDD= mapRDD.groupByKey()
    groupRDD.collect().foreach(println)
    sc.stop()
  }

Spark---持久化_第3张图片

RDD Cache 缓存

cache 操作会增加血缘关系,不改变原有的血缘关系
RDD 通过 Cache 或者 Persist 方法将前面的计算结果缓存,默认情况下会把数据以缓存在 JVM 的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 算子时,该 RDD 将会被缓存在计算节点的内存中,并供后面重用。

  def main(args: Array[String]): Unit = {
    val sparkConf: SparkConf = new SparkConf().setMaster("local").setAppName("wordcount")
    val sc = new SparkContext(sparkConf)
    println("===========reduceByKey操作=============")
    val list = List("Hello Scala", "Hello Spark")
    val rdd: RDD[String] = sc.makeRDD(list)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(word =>{
      //这里map操作设置了打印操作,来方便区别
      println("@@@@@@@@@@")
      (word,1)
    })
    /**
     * cache默认持久化操作,只能将数据保存到内存中,
     * 如果想要保存到磁盘当中
     * 需要更改存储级别
     */
    mapRDD.cache()//放入内存当中
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_ + _)
    reduceRDD.collect().foreach(println)
    println("===========groupByKey操作=============")
    val groupRDD= mapRDD.groupByKey()
    groupRDD.collect().foreach(println)
    sc.stop()
  }

Spark---持久化_第4张图片

RDD Persist 缓存

不改变原有的血缘关系
保存成临时文件,作业结束后,文件会消失

可以更改存储级别
mapRdd.persist(StorageLevel.MEMORY_AND_DISK_2)

存储级别

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)

Spark---持久化_第5张图片

  • 缓存有可能丢失,或者存储于内存的数据由于内存不足而被删除,RDD 的缓存容错机制保证了即使缓存丢失也能保证计算的正确执行。通过基于 RDD 的一系列转换,丢失的数据会被重算,由于 RDD 的各个 Partition 是相对独立的,因此只需要计算丢失的部分即可,并不需要重算全部 Partition。
  • Spark 会自动对一些 Shuffle 操作的中间数据做持久化操作(比如:reduceByKey)。这样做的目的是为了当一个节点 Shuffle 失败了避免重新计算整个输入。但是,在实际使用的时候,如果想重用数据,仍然建议调用 persist 或 cache。
  def main(args: Array[String]): Unit = {
    val sparkConf: SparkConf = new SparkConf().setMaster("local").setAppName("wordcount")
    val sc = new SparkContext(sparkConf)
    println("===========reduceByKey操作=============")
    val list = List("Hello Scala", "Hello Spark")
    val rdd: RDD[String] = sc.makeRDD(list)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(word =>{
      //这里map操作设置了打印操作,来方便区别
      println("@@@@@@@@@@")
      (word,1)
    })
    /**
     * 如果想要保存到磁盘当中
     * 需要更改存储级别
     * 持久化操作必须在行动算子执行时完成的
     */
    mapRDD.persist(StorageLevel.DISK_ONLY)
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_ + _)
    reduceRDD.collect().foreach(println)
    println("===========groupByKey操作=============")
    val groupRDD= mapRDD.groupByKey()
    groupRDD.collect().foreach(println)
    sc.stop()
  }

RDD CheckPoint 检查点

检查点路径保存的文件,当作业执行完毕后,不会被删除

  • 所谓的检查点其实就是通过将 RDD 中间结果写入磁盘
  • 由于血缘依赖过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销
  • 对 RDD 进行 checkpoint 操作并不会马上被执行,必须执行 Action 操作才能触发
  • 检查点存储路径:Checkpoint的数据通常是存储在HDFS等容错、高可用的文件系统
  • 检查点数据存储格式为:二进制的文件
  • 检查点切断血缘:在Checkpoint的过程中,该RDD的所有依赖于父RDD中的信息将全部被移除
  • 检查点触发时间:对RDD进行Checkpoint操作并不会马上被执行,必须执行Action操作才能触发。但是检查点为了数据安全,会从血缘关系的最开始执行一遍
  • 建议对checkpoint()的RDD使用Cache缓存,这样checkpoint的job只需从Cache缓存中读取数据即可,否则需要再从头计算一次RDD
    以WordCount为例,这里检查点路径设置保存在本地
  def main(args: Array[String]): Unit = {
    val sparkConf: SparkConf = new SparkConf().setMaster("local").setAppName("wordcount")
    val sc = new SparkContext(sparkConf)
    // 设置检查点路径
    sc.setCheckpointDir("cp")
    val list = List("Hello Scala", "Hello Spark")
    val rdd: RDD[String] = sc.makeRDD(list)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(word =>{
      println("@@@@@@@@@@@@")
      (word,1)
    })
    /**
     * 检查点
     * checkpoint
     * 需要落盘,需要指定检查点保存路径
     * 可以重复使用
     * 检查点路径保存的文件,当作业执行完毕后,不会被删除
     * 一般保存路径都是在分布式储存系统:HDFS
     */
      mapRDD.checkpoint()
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_ + _)
    reduceRDD.collect().foreach(println)
    println("==============================")
    val groupRDD= mapRDD.groupByKey()
    groupRDD.collect().foreach(println)
    sc.stop()
  }

执行过程中,会切断血缘关系。重新建立新的血缘关系。因为读取数据的数据源发生了改变
Spark---持久化_第6张图片
在这里插入图片描述

可以配合cache使用,这样checkpoint的job只需从Cache缓存中读取数据即可

// 增加缓存,避免再重新跑一个 job 做 checkpoint
mapRDD.cache()
// 数据检查点:针对 wordToOneRdd 做检查点计算
mapRDD.checkpoint()

缓存和检查点区别

cache

  • 将数据临时存储在内存中进行数据重用
  • 会在血缘关系中添加新的依赖。一旦出现问题,可以从头读取数据

persist

  • 将数据临时存储在磁盘文件中进行数据重用
  • 涉及到磁盘IO,性能较低,但是数据安全
  • 如果作业执行完成,临时保存的数据文件就会丢失

checkpoint

  • 将数据长久地保存在磁盘文件中进行数据重用
  • 涉及到磁盘IO,性能较低,但是数据是安全的
  • 为了保证数据安全,所以一般情况下,会独立执行作业
  • 执行过程中,会切断血缘关系。重新建立新的血缘关系。因为读取数据的数据源发生了改变。
  • checkpoint等同于新的数据源
  • 为了能够提高效率,一般情况下,是需要和cache联合使用
    总结
    1)Cache 缓存只是将数据保存起来,不切断血缘依赖。Checkpoint 检查点切断血缘依赖。
    2)Cache 缓存的数据通常存储在磁盘、内存等地方,可靠性低。Checkpoint 的数据通常存储在 HDFS 等容错、高可用的文件系统,可靠性高。
    3)建议对 checkpoint()的 RDD 使用 Cache 缓存,这样 checkpoint 的 job 只需从 Cache 缓存中读取数据即可,否则需要再从头计算一次 RDD

你可能感兴趣的:(Spark,spark,scala,大数据)