Spark中Cache,persist和Checkpoint的区别

  • cache :将数据临时存储在内存中进行数据重用,如果作业执行完毕,临时保存的数据文件就会丢失
  • persist :将数据临时存储在磁盘文件中进行数据重用,涉及到磁盘I0,性能较低,但是数据安全,如果作业执行完毕,临时保存的数据文件就会丢失
  • checkpoint :将数据长久地保存在磁盘文件中进行数据重用,涉及到磁盘Io,性能较低,但是数据安全。为了保证数据安全,所以一般情况下,会独立执行作业,所以会有重复操作,为了优化性能,往往和cache一起使用。

RDD结构本身不记录数据,只记录操作,所以简单对RDD的复用并不是说这个操作只执行一次,真实还是会执行两次,如下面的代码可以看出,两个action触发了转换函数的两次执行,即他们的lineage血脉分别单独执行了一次。


object SparkWordCount2 {
  def main(args: Array[String]): Unit = {
    var sparkConf= new SparkConf().setMaster("local").setAppName("WordCount")
    var sc =  new SparkContext(sparkConf)
    val rdd: RDD[String] = sc.makeRDD(List("hello word, hello spark"))
    val wordRDD:RDD[String] = rdd.flatMap(_.split(" "))
    val wordToOneRDD: RDD[(String, Int)] = wordRDD.map(iter=>{
      println("转换函术执行了") //总共4个单词,所以map操作一次共打印4个
      (iter,1)})
    val wordToCountRDD1: RDD[(String, Int)] =wordToOneRDD.reduceByKey((_+_)) //两个不同的action 操作会分别从源头rdd执行转换
    val wordToCountRDD2: RDD[(String, Iterable[Int])] = wordToOneRDD.groupByKey(2) //两个不同的action 操作会分别从源头rdd执行转换
    wordToCountRDD1.collect().foreach(println)
    wordToCountRDD2.collect().foreach(println)
    sc.stop()
  }
}

输出:

转换函术执行了
转换函术执行了
转换函术执行了
转换函术执行了
(spark,1)
(word,1)
(hello,2)
转换函术执行了
转换函术执行了
转换函术执行了
转换函术执行了
(hello,CompactBuffer(1, 1))
(word,CompactBuffer(1))
(spark,CompactBuffer(1))

Process finished with exit code 0

要想实现复用,或者避免重复进行很长的转换函数,可以使用cache或persist缓存数据,例如在上面出现宽依赖之前使用,即

object SparkWordCount2 {
  def main(args: Array[String]): Unit = {
    var sparkConf= new SparkConf().setMaster("local").setAppName("WordCount")
    var sc =  new SparkContext(sparkConf)
    val rdd: RDD[String] = sc.makeRDD(List("hello word, hello spark"))
    val wordRDD:RDD[String] = rdd.flatMap(_.split(" "))
    val wordToOneRDD: RDD[(String, Int)] = wordRDD.map(iter=>{
      println("转换函术执行了") //总共4个单词,所以map操作一次共打印4个
      (iter,1)})
//    wordToOneRDD.persist()
    wordToOneRDD.cache()
    val wordToCountRDD1: RDD[(String, Int)] =wordToOneRDD.reduceByKey((_+_)) //两个不同的action 操作会分别从源头rdd执行转换
    val wordToCountRDD2: RDD[(String, Iterable[Int])] = wordToOneRDD.groupByKey(2) //两个不同的action 操作会分别从源头rdd执行转换
    wordToCountRDD1.collect().foreach(println)
    wordToCountRDD2.collect().foreach(println)
    sc.stop()
  }
}

这样最终map函数只会执行一次,输出如下:

转换函术执行了
转换函术执行了
转换函术执行了
转换函术执行了
(spark,1)
(word,,1)
(hello,2)
(word,,CompactBuffer(1))
(hello,CompactBuffer(1, 1))
(spark,CompactBuffer(1))

Process finished with exit code 0

但是persist或cache的数据只是临时的,job执行完后会失效,(所以也不需传入保存的路径参数)。

为了持久保存,可以使用检查点checkpoint,使用时还应和cache等配合使用,因为为了最求可靠,checkpoint会对每个job执行一遍(每个action对应一个job)。(一般保存在HDFS等分布式文件系统上,要传入相应保存路径)
使用时代码如下:

object SparkWordCount2 {
  def main(args: Array[String]): Unit = {
    var sparkConf= new SparkConf().setMaster("local").setAppName("WordCount")
    var sc =  new SparkContext(sparkConf)
    val rdd: RDD[String] = sc.makeRDD(List("hello word, hello spark"))
    val wordRDD:RDD[String] = rdd.flatMap(_.split(" "))
    val wordToOneRDD: RDD[(String, Int)] = wordRDD.map(iter=>{
      println("转换函术执行了") //总共4个单词,所以map操作一次共打印4个
      (iter,1)})
//    wordToOneRDD.persist()
    wordToOneRDD.cache()
    wordToOneRDD.checkpoint("path on hdfs")//填入对应分布式文件系统上保存的路径
    val wordToCountRDD1: RDD[(String, Int)] =wordToOneRDD.reduceByKey((_+_)) //两个不同的action 操作会分别从源头rdd执行转换
    val wordToCountRDD2: RDD[(String, Iterable[Int])] = wordToOneRDD.groupByKey(2) //两个不同的action 操作会分别从源头rdd执行转换
    wordToCountRDD1.collect().foreach(println)
    wordToCountRDD2.collect().foreach(println)
    sc.stop()
  }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值