spark从入门到放弃七: 共享变量

122 篇文章 15 订阅
43 篇文章 1 订阅

文章地址:http://www.haha174.top/article/details/257359
项目源码:https://github.com/haha174/spark.git
spark 一个非常重要的特性就是共享变量,默认情况下如果一个算子函数中使用到了某个外部的变量,那么这个变量的值会被拷贝到每个task 中,此时每个task 只能操作自己那份变量副本。如果多个task 想要共享某个变量这种方式是做不到的。
spark 为此提供了两种共享变量,一种是Broadcast(广播变量),另一种是Accumulator(累加变量)。broadcast Variable 会将使用到的变量。仅仅为每个节点拷贝一份。更大的用处是优化性能。减少网络传输以及内存的消耗。Accumulator则可以让多个task 共同操作一份变量,主要可以进行累加操作。
默认情况下,函数的算子使用到了外部的变量,会拷贝一份到执行这个函数的每一个task中,如果那个变量特别大的话那么想想看这个网络传输是不是特别的大,而且在每个节点上,占用的内存空间,是不是也特别的大。
不使用共享变量如图所示:
这里写图片描述
如果把算子函数使用到的变量做成共享变量的话那么每个变量,只会拷贝一份到每个节点上,节点上所有的task ,都会共享这个一份变量。
这里写图片描述
spark 提供Broadcast Variable 是只读的,并且每个节点上会只有一个副本,而不会给每个task 拷贝一份副本,因此最大其最大作用,就是减少到各个节点的网络传输消耗,以及在各个节点上的内存消耗。此外spark自己内部也使用了高效的广播算法来减少网络消耗。
可以通过调用SparkContext的broadcast()方法。来针对某个变量创建广播变量。然后在算子的范围内部使用到广播变量时,每个节点只会拷贝一份副本。每个节点可以使用广播变量的value()方法取值。备注广播变量时只读的。
下面给出一个java 示例:

public class BroadCastDemo {
    public static void  main(String[] args){
        SparkConf conf=new SparkConf().setAppName("BroatCast").setMaster("local");
        JavaSparkContext sc=new JavaSparkContext(conf);
        List<Integer> listNumber= Arrays.asList(1,2,3,4,5);
        final int factor=3;
        //在java  中 创建广播变量
        final Broadcast<Integer> factoryBroatCast=sc.broadcast(factor);

        JavaRDD<Integer> rddList=sc.parallelize(listNumber);
        JavaRDD<Integer> result=rddList.map(new Function<Integer, Integer>() {
            public Integer call(Integer integer) throws Exception {
                //在java  中 获取广播变量
               return integer*factoryBroatCast.value();
            }
        });
        result.foreach(new VoidFunction<Integer>() {
            @Override
            public void call(Integer integer) throws Exception {
                System.out.println(integer);
            }
        });
        sc.close();
    }
}

下面给出一个scala 示例

object BroadCast {
  def main(args: Array[String]): Unit = {
    val conf=new SparkConf().setMaster("local").setAppName("BroadCast")
    val sc=new SparkContext(conf)
    var factor=3
    var fac=sc.broadcast(factor);
    var numAray=Array(1,2,3,4,5)
    var numList=sc.parallelize(numAray)
    var numResult=numList.map(num=>num*fac.value)
    numResult.foreach(num=>println(num))
  }
}

Accumulator

spark 提供Accumulator 主要针对于多个节点对一个变量进行操作,Accumulator只提供累加的功能,但是却给我们提供了多个task 操作一个变量的功能。但是task只能对Accumulator进行累加操作却不能读取他的值。是有Driver 程序可以读取Accumulator.
下面给出java 示例


public class AccumulatorDemo {
    public static void main(String[] args){
        SparkConf conf=new SparkConf().setAppName("BroatCast").setMaster("local");
        JavaSparkContext sc=new JavaSparkContext(conf);
        Accumulator<Integer> sum=sc.accumulator(0);
        List<Integer> listNumber= Arrays.asList(1,2,3,4,5);
        JavaRDD<Integer> rddList=sc.parallelize(listNumber);
       rddList.foreach(new VoidFunction<Integer>(){
            public void call(Integer integer) throws Exception {
                //在java  中 获取广播变量
                sum.add(integer);
            }
    });
       System.out.println(sum.value());
    }
}

下面给出scala 示例:

object AccumulatorDemo {
  def main(args: Array[String]): Unit = {
      val conf=new SparkConf().setMaster("local").setAppName("AccumulatorDemo")
      val sc=new SparkContext(conf)
      val accum = sc.accumulator(0)
      sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum += x)
      println(accum)

  }

累加器与容错

对于失效节点和慢节点,Spark会自动通过重新执行(re-executing)失效任务或慢任务。而有时,即使没有节点失效,Spark可能会需要重新执行一遍tasks来重建一个被移出内存的缓存值,这就导致同一数据上的同一函数可能会因此执行多次。
对于在RDD转换(Transformation)操作中的累加器,一个累加器的更新可能会出现多次。出现这种现象的一种可能情况是,一个被缓存,但是不经常使用的RDD被第一次弹出LRU cache队列,但是之后又需要使用了。这时RDD会根据其血统(lineage)被重新计算,而累加器上的更新也因此多执行了一遍,并返回给driver。因此,建议在转换操作中使用的累加器仅用于调试目的。

欢迎关注,更多福利

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值