Spark:广播变量和累加器的使用

一、广播变量和累加器

1.1 广播变量:

广播变量允许程序员将一个只读的变量缓存在每台机器上,而不用在任务之间传递变量。广播变量可被用于有效地给每个节点一个大输入数据集的副本。Spark还尝试使用高效地广播算法来分发变量,进而减少通信的开销。
Spark的动作通过一系列的步骤执行,这些步骤由分布式的shuffle操作分开。Spark自动地广播每个步骤每个任务需要的通用数据。这些广播数据被序列化地缓存,在运行任务之前被反序列化出来。这意味着当我们需要在多个阶段的任务之间使用相同的数据,或者以反序列化形式缓存数据是十分重要的时候,显式地创建广播变量才有用。

1.2 累加器:

累加器是仅仅被相关操作累加的变量,因此可以在并行中被有效地支持。它可以被用来实现计数器和总和。Spark原生地只支持数字类型的累加器,编程者可以添加新类型的支持。如果创建累加器时指定了名字,可以在Spark的UI界面看到。这有利于理解每个执行阶段的进程。(对于python还不支持)
累加器通过对一个初始化了的变量v调用SparkContext.accumulator(v)来创建。在集群上运行的任务可以通过add或者”+=”方法在累加器上进行累加操作。但是,它们不能读取它的值。只有驱动程序能够读取它的值,通过累加器的value方法。

二.Java和Scala版本的实战演示

2.1 Java版本:


/**
 * 实例:利用广播进行黑名单过滤!
 * 检查新的数据 根据是否在广播变量-黑名单内,从而实现过滤数据。
 */
public class BroadcastAccumulator {

    /**
     * 创建一个List的广播变量
     *
     */
    private static volatile Broadcast<List<String>> broadcastList = null;

    /**
     * 计数器!
     */
    private static volatile Accumulator<Integer> accumulator = null;

    public static void main(String[] args) {

        SparkConf conf = new SparkConf().setMaster("local[2]").
                setAppName("WordCountOnlineBroadcast");

        JavaStreamingContext jsc = new JavaStreamingContext(conf, Durations.seconds(5));


        /**
         * 注意:分发广播需要一个action操作触发。
         * 注意:广播的是Arrays的asList 而非对象的引用。广播Array数组的对象引用会出错。
         * 使用broadcast广播黑名单到每个Executor中!
         */
        broadcastList = jsc.sc().broadcast(Arrays.asList("Hadoop","Mahout","Hive"));

        /**
         * 累加器作为全局计数器!用于统计在线过滤了多少个黑名单!
         * 在这里实例化。
         */
        accumulator = jsc.sparkContext().accumulator(0,"OnlineBlackListCounter");


        JavaReceiverInputDStream<String> lines = jsc.socketTextStream("Master", 9999);


        /**
         * 这里省去flatmap因为名单是一个个的!
         */
        JavaPairDStream<String, Integer> pairs = lines.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String word) {
                return new Tuple2<String, Integer>(word, 1);
            }
        });

        JavaPairDStream<String, Integer> wordsCount = pairs.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer v1, Integer v2) {
                return v1 + v2;
            }
        });

        /**
         * Funtion里面 前几个参数是 入参。
         * 后面的出参。
         * 体现在call方法里面!
         *
         */
        wordsCount.foreach(new Function2<JavaPairRDD<String, Integer>, Time, Void>() {
            @Override
            public Void call(JavaPairRDD<String, Integer> rdd, Time time) throws Exception {
                rdd.filter(new Function<Tuple2<String, Integer>, Boolean>() {
                    @Override
                    public Boolean call(Tuple2<String, Integer> wordPair) throws Exception {
                        if (broadcastList.value().contains(wordPair._1)) {

                            /**
                             * accumulator不仅仅用来计数。
                             * 可以同时写进数据库或者缓存中。
                             */
                            accumulator.add(wordPair._2);
                            return false;
                        }else {
                            return true;
                        }
                    };
                    /**
                     * 广播和计数器的执行,需要进行一个action操作!
                     */
                }).collect();

                System.out.println("广播器里面的值"+broadcastList.value());
                System.out.println("计时器里面的值"+accumulator.value());
                return null;
            }
        });


        jsc.start();
        jsc.awaitTermination();
        jsc.close();

    }

    }


2.2 Scala版本

package com.Streaming

import java.util

import org.apache.spark.streaming.{Duration, StreamingContext}
import org.apache.spark.{Accumulable, Accumulator, SparkContext, SparkConf}
import org.apache.spark.broadcast.Broadcast

/**
  * Created by lxh on 2016/6/30.
  */
object BroadcastAccumulatorStreaming {

  /**
    * 声明一个广播和累加器!
    */
  private var broadcastList:Broadcast[List[String]]  = _
  private var accumulator:Accumulator[Int] = _

  def main(args: Array[String]) {

    val sparkConf = new SparkConf().setMaster("local[4]").setAppName("broadcasttest")
    val sc = new SparkContext(sparkConf)

    /**
      * duration是ms
      */
    val ssc = new StreamingContext(sc,Duration(2000))
   // broadcastList = ssc.sparkContext.broadcast(util.Arrays.asList("Hadoop","Spark"))
    broadcastList = ssc.sparkContext.broadcast(List("Hadoop","Spark"))
    accumulator= ssc.sparkContext.accumulator(0,"broadcasttest")

    /**
      * 获取数据!
      */
    val lines = ssc.socketTextStream("localhost",9999)

    /**
      * 1.flatmap把行分割成词。
      * 2.map把词变成tuple(word,1)
      * 3.reducebykey累加value
      * (4.sortBykey排名)
      * 4.进行过滤。 value是否在累加器中。
      * 5.打印显示。
      */
    val words = lines.flatMap(line => line.split(" "))

    val wordpair = words.map(word => (word,1))

    wordpair.filter(record => {broadcastList.value.contains(record._1)})


    val pair = wordpair.reduceByKey(_+_)

    /**
      * 这个pair 是PairDStream<String, Integer>
      * 查看这个id是否在黑名单中,如果是的话,累加器就+1
      */
/*    pair.foreachRDD(rdd => {
      rdd.filter(record => {

        if (broadcastList.value.contains(record._1)) {
          accumulator.add(1)
          return true
        } else {
          return false
        }

      })

    })*/

    val filtedpair = pair.filter(record => {
        if (broadcastList.value.contains(record._1)) {
          accumulator.add(record._2)
          true
        } else {
          false
        }

     }).print

    println("累加器的值"+accumulator.value)

   // pair.filter(record => {broadcastList.value.contains(record._1)})

   /* val keypair = pair.map(pair => (pair._2,pair._1))*/

    /**
      * 如果DStream自己没有某个算子操作。就通过转化transform!
      */
   /* keypair.transform(rdd => {
      rdd.sortByKey(false)//TODO
    })*/
    pair.print()
    ssc.start()
    ssc.awaitTermination()

  }

}

相关:

1.Spark自定义累加器的实现

2.广播变量的原理及在调优中的使用

原文参考:https://blog.csdn.net/lxhandlbb/article/details/51931713

猜你喜欢

转载自blog.csdn.net/weixin_38750084/article/details/82972722