Spark RDD的持久化(缓存、检查点、广播变量和累加器)

RDD持久化1:缓存

RDD缓存机制
缓存数据至内存/磁盘,可大幅度提升Spark应用性能。

  • cache=persist(MEMORY)

  • persist
    缓存策略:StorageLevel

  • MEMORY_ONLY(默认)

  • MEMORY_AND_DISK

  • DISK_ONLY


  • 缓存应用场景

  • 从文件加载数据后,因为重新获取文件成本较高;

  • 经过较多的算子变换之后,重新计算成本较高;

  • 单个非常消耗资源的算子之后。

注意事项
cache()或persist()遇到Action算子完成后才生效;
代码演示:

 val rdd1 = sc.parallelize(List(("A",1),("A",2),("B",1),("B",3),("C",1)))
    rdd1.cache() //此时还未生效
    rdd1.count() //经过一个Action算子后,cache生效
    rdd1.collect().foreach(println)

从上面的代码好像看不出有什么区别,那么就用一个更大的数据来做一下演示。

 val rdd2 = sc.textFile("data/users.csv")
    rdd2.cache()
    rdd2.count()

    //开始执行的时间
    var start = System.currentTimeMillis()
    println(rdd2.count())
    //结束时间
    var stop = System.currentTimeMillis()
    println("使用的时间是:"+(stop-start))

    //取消缓存所用的时间
     start = System.currentTimeMillis()
    rdd2.unpersist()//取消缓存
    println(rdd2.count())
     stop = System.currentTimeMillis()
    println("取消后使用的时间是:"+(stop-start))

结果:

38210
使用的时间是:36
38210
取消后使用的时间是:73

可以明显看出所用时间差别还是挺大的。
persist
作用与cache相同。

//使用persist,与cache效果相同
    rdd2.persist(StorageLevel.MEMORY_ONLY)
    rdd2.count()
    //开始执行的时间
    var start = System.currentTimeMillis()
    println(rdd2.count())
    //结束时间
    var stop = System.currentTimeMillis()
    println("使用的时间是:"+(stop-start))

    //取消缓存所用的时间
    start = System.currentTimeMillis()
    rdd2.unpersist()
    println(rdd2.count())
    stop = System.currentTimeMillis()
    println("取消后使用的时间是:"+(stop-start))

结果:

38210
使用的时间是:35
38210
取消后使用的时间是:63

RDD持久化2:检查点

与快照类似。它与缓存的区别是:
检查点会删除RDD lineage(血统、遗传),而缓存不会;
SparkContext被销毁后,检查点数据不会被删除。

 //检查点缓存路径
    sc.setCheckpointDir("data/save2")
    val rdd = sc.makeRDD(List(("A",1),("A",2),("B",1),("B",3),("C",1)))
    rdd.checkpoint()
    rdd.collect //生成快照
    println(rdd.isCheckpointed) //是否是检查点,返回的是布尔值
    println(rdd.getCheckpointFile) //得到检查点文件绝对路径
    println(rdd.toDebugString) //查看血缘关系

RDD共享变量1:广播变量

允许开发者将一个只读变量(Driver端)缓存到每个节点(Executor)上,而不是每个任务传递一个副本;
注意:

  • Driver端变量在每个Executor每个Task保存一个变量副本;
  • Driver端广播变量在每个Executor只保存一个变量副本。
 val arr = Array("hello","hi")
    //广播
    val brd = sc.broadcast(arr)
    val rdd = sc.makeRDD(List((1,"sam"),(2,"sally"),(3,"john")))
    val result = rdd.mapValues(x => {
      brd.value(0) + ":" + x
    })
    result.foreach(println)
    //不使用广播.效率不如广播
    val rsult2 = rdd.mapValues(x => {
      arr(1) + ":" + x
    })
    rsult2.foreach(println)

Java版:

    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("broadcast").setMaster("local[*]");
        JavaSparkContext sc = new JavaSparkContext(conf);

        int factor = 2;
        Broadcast<Integer> broadValue = sc.broadcast(factor);
        List<Integer> list = Arrays.asList(5, 6, 7, 8, 9);
        JavaRDD<Integer> rdd = sc.parallelize(list);
        JavaRDD<Integer> map = rdd.map(new Function<Integer, Integer>() {
            @Override
            public Integer call(Integer integer) throws Exception {
                return integer * broadValue.value();
            }
        });
        map.foreach(new VoidFunction<Integer>() {
            @Override
            public void call(Integer integer) throws Exception {
                System.out.println(integer);
            }
        });
sc.close();
    }

RDD共享变量2:累加器

只匀速added操作,常用于实现计数
例1:

val rdd = sc.makeRDD(1 to 5)
    val acc = sc.accumulator(5)
    rdd.foreach(x=>acc+=x)
    println(acc.value)

例2:

val accum = sc.accumulator(0,"My Accum")
    sc.makeRDD(Array(1,2,3,4,5)).foreach(x=>accum+=x)
    println(accum.value)

累加器特性:

  1. 累加器也是也具有懒加载属性,只有在action操作执行时,才会强制触发计算求值;
  2. 累加器的值只可以在Driver端定义初始化,在Executor端更新,不能在Executor端进行定义初始化,不能在Executor端通过[.value]获取值,任何工作节点上的Task都不能访问累加器的值;
  3. 闭包里的执行器代码可以使用累加器的 += 方法(在Java中是 add )增加累加器的值。

RDD分区设计

  • 分区大小限制为2GB;
  • 分区如果太少:
    不利于开发;
    更容易受数据倾斜影响;
    groupBy, reduceByKey, sortByKey等内存压力增大
  • 分区过多:
    Shuffle开销越大
    创建任务开销越大

建议在创建RDD分区时,每个分区大约128MB。如果分区小于但接近2000,则设置为大于2000.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值