JavaSpark-编程进阶-广播变量

来源:互联网 发布:dlp数据泄露防护系统 编辑:程序博客网 时间:2024/06/05 19:01

程序高效地向所有worker发送一个较大的只读值(查询表,机器学习特征向量),供spark操作使用。
spark会自动将闭包中所有引用的到的变量发送到工作节点上,但低效:

  • 默认的发送机制是专门为小任务进行优化的
  • 多个并行操作中使用同一个变量,spark会为每一个操作分别发送
import java.util.Arrays;import java.util.List;import org.apache.spark.Accumulator;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import org.apache.spark.broadcast.Broadcast;import org.apache.spark.streaming.Durations;import org.apache.spark.streaming.api.java.JavaPairDStream;import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;import org.apache.spark.streaming.api.java.JavaStreamingContext;import scala.Tuple2;/** * 实例:利用广播进行黑名单过滤! * 检查新的数据 根据是否在广播变量-黑名单内,从而实现过滤数据。 */public class BroadCastDemo { /**  * 创建一个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(); } }

广播变量使Broadcast[T]的一个对象,可以通过Broad value获得值,这个值只会被各节点发送一次。(使用高效BitTorrent通信机制)

使用广播变量
(Java)SparkContext.Broadcast创建出Broadcast[T]
value属性访问该对象的值
变量只会被发送到各节点一次,并且是一个只读值


广播的优化
当广播一个比较大的值时,选择既快又好的序列化格式是很重要的,因为如果序列化对象的时间长或者传送花费的时间太久,这就很容易变成瓶颈。
Java API默认使用java的序列化库,它除基本类型的数组外的其他对象都比较低效。
可使用spark.serializer属性选择另一个序列化库来优化序列化过程
或者自己实现序列化方式

原创粉丝点击