Spark--RDD持久化

引言

要实现同一个rdd的分组聚合操作和分组操作
通过以下代码会发现代码的重复率很高,性能很低
如果一个RDD需要重复使用,那么需要从头再次执行来获取数据
RDD对象可以重用,但是数据无法重用
这时候我们就可以思考如何能够使RDD的数据也能够重用呢?

object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map((_,1))
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val rdd1: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD1: RDD[String] = rdd1.flatMap(_.split(" "))
    val mapRDD1: RDD[(String, Int)] = flatRDD1.map((_,1))
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD1.groupByKey()
    groupRDD1.collect().foreach(println)


    sc.stop()
  }
}
(spark,1)
(scala,1)
(hello,2)
----------------------
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

一. RDD Cache缓存

RDD 通过Cache 或者 Persist 方法将前面的计算结果缓存,默认情况下会把数据以缓存在 JVM 的堆内存中。但是并不是这两个方法被调用时立即缓存,而是触发后面的 action 算子时,该RDD 将会被缓存在计算节点的内存中,并供后面重用。 所以持久化操作必须在行动算子执行时完成的。
RDD对象的持久化操作不一定是为了重用,在数据执行较长,或数据比较重要的场合也可以采用持久化操作
在这里插入图片描述
cache默认持久化的操作,底层调用的是Persist的MEMORY_ONLY,只能将数据保存到内存中,如果想要保存到磁盘文件,需要更改存储的级别
未设置缓存

object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(spark,1)
(scala,1)
(hello,2)
----------------------
map执行一次
map执行一次
map执行一次
map执行一次
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

设置缓存

object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"))
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    //设置了缓存
    //mapRDD.cache()
    mapRDD.persist(StorageLevel.DISK_ONLY)
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)
    
    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(spark,1)
(scala,1)
(hello,2)
----------------------
(spark,CompactBuffer(1))
(scala,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

二. RDD CheckPoint检查点

所谓的检查点其实就是通过将RDD 中间结果写入磁盘 由于血缘依赖过长会造成容错成本过高,这样就不如在中间阶段做检查点容错,如果检查点之后有节点出现问题,可以从检查点开始重做血缘,减少了开销。
对 RDD 进行 checkpoint 操作并不会马上被执行,必须执行 Action 操作才能触发。

object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setCheckpointDir("datas\\checkpoint")

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"),1)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    //checkpoint需要落盘,需要指定检查点保存路径
    //检查点路径保存的文件,当作业执行完毕后,不会被删除
    //一般保存路径都是在分布式存储系统:HDFS
    mapRDD.checkpoint()
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
map执行一次
(scala,1)
(spark,1)
(hello,2)
----------------------
(scala,CompactBuffer(1))
(spark,CompactBuffer(1))
(hello,CompactBuffer(1, 1))

在这里插入图片描述

三. 缓存和检查点区别

  • cache和persist只是将数据保存起来,不切断血缘依赖,会在血缘关系中添加新的依赖,一旦出现问题,可以从头读取数据,而Checkpoint 检查点会切断血缘依赖,重新建立新的血缘关系,checkpoint等同于改变数据源
  • 缓存的数据通常存储在磁盘、内存等地方,可靠性低,如果作业执行完毕,临时保存的数据文件就会丢失,Checkpoint 的数据通常存储在HDFS等高容错、高可用的文件系统,涉及到磁盘IO,性能较低,但数据安全,可靠性高。
  • 建议对checkpoint()的RDD 使用Cache 缓存,和cache联合使用,这样 checkpoint 的 job 只需从 Cache缓存中读取数据即可,否则需要再从头计算一次RDD。
object Spark_rdd_01 {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("RDD").setMaster("local[*]")
    val sc = new SparkContext(conf)
    sc.setCheckpointDir("datas\\checkpoint")

    val rdd: RDD[String] = sc.makeRDD(List("hello spark","hello scala"),1)
    val flatRDD: RDD[String] = rdd.flatMap(_.split(" "))
    val mapRDD: RDD[(String, Int)] = flatRDD.map(x=>{
      println("map执行一次")
      (x,1)
    })
    mapRDD.cache()
    mapRDD.checkpoint()
    val reduceRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    reduceRDD.collect().foreach(println)
    println("----------------------")
    val groupRDD1: RDD[(String, Iterable[Int])] = mapRDD.groupByKey()
    groupRDD1.collect().foreach(println)

    sc.stop()
  }
}
map执行一次
map执行一次
map执行一次
map执行一次
(scala,1)
(spark,1)
(hello,2)
----------------------
(scala,CompactBuffer(1))
(spark,CompactBuffer(1))
(hello,CompactBuffer(1, 1))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值