SparkStreaming简介

SparkStreaming是流式处理框架,是Spark API的扩展,支持可扩展、高吞吐量、容错的实时数据流处理,实时数据的来源可以是:Kafka, Flume, Twitter, ZeroMQ或者TCP sockets,并且可以使用高级功能的复杂算子来处理流数据。例如:map,reduce,join,window 。最终,处理后的数据可以存放在文件系统,数据库等,方便实时展现。

spark移动计算不移动数据 spark数据流_spark

Spark Streaming在内部的处理机制是,接收实时流的数据,并根据一定的时间间隔拆分成一批批的数据,然后通过Spark Engine处理这些批数据,最终得到处理后的一批批结果数据。对应的批数据,在Spark内核对应一个RDD实例,因此,对应流数据的DStream可以看成是一组RDDs,即RDD的一个序列。通俗点理解的话,在流数据分成一批一批后,通过一个先进先出的队列,然后 Spark Engine从该队列中依次取出一个个批数据,把批数据封装成一个RDD,然后进行处理,这是一个典型的生产者消费者模型。

4. SparkStreaming算子操作

node1: nc -lk 9999 连接端口

1、foreachRDD 算子
public class SparkStreaming {
    public static void main(String[] args) throws InterruptedException {
        SparkConf sparkConf = new SparkConf().setMaster("local[2]").setAppName("spark-streaming");
        JavaSparkContext javaSparkContext = new JavaSparkContext(sparkConf);
        javaSparkContext.setLogLevel("warn");
        // 参数: 批处理时间
        JavaStreamingContext javaStreamingContext = new JavaStreamingContext(javaSparkContext, Durations.seconds(5));
        // 监听node1 9999 端口
        JavaReceiverInputDStream<String> line = javaStreamingContext.socketTextStream("node1",9999);

        JavaDStream<String> words = line.flatMap(new FlatMapFunction<String, String>() {
            @Override
            public Iterator<String> call(String s) throws Exception {
                return Arrays.asList(s.split(" ")).iterator();
            }
        });

        JavaPairDStream<String, Integer> wordsMap = words.mapToPair(new PairFunction<String, String, Integer>() {
            @Override
            public Tuple2<String, Integer> call(String s) throws Exception {
                return new Tuple2<>(s, 1);
            }
        });

        JavaPairDStream<String, Integer> reudceMap = wordsMap.reduceByKey(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) throws Exception {
                return integer + integer2;
            }
        });
        // sparkstreamming foreachRdd 算子, 不会触发计算, 需要action算子触发
        reudceMap.foreachRDD(new VoidFunction<JavaPairRDD<String, Integer>>() {
            @Override
            public void call(JavaPairRDD<String, Integer> temRdd) throws Exception {
                JavaPairRDD<String, Integer> javaPairRDD = temRdd.mapToPair(new PairFunction<Tuple2<String, Integer>, String, Integer>() {
                    @Override
                    public Tuple2<String, Integer> call(Tuple2<String, Integer> tuple2) throws Exception {
                        return new Tuple2<String, Integer>(tuple2._1, tuple2._2);
                    }
                });
                // action算子, 触发计算
                javaPairRDD.foreach(new VoidFunction<Tuple2<String, Integer>>() {
                    @Override
                    public void call(Tuple2<String, Integer> tuple2) throws Exception {
                        System.out.println("-------"+tuple2._1+":"+tuple2._2);
                    }
                });
            }
        });

        // 输出
        //reudceMap.print();
        javaStreamingContext.start();
        javaStreamingContext.awaitTermination();
    }
}

2、广播使用

// 广播
	SparkContext context = temRdd.context();
	JavaSparkContext javaSparkContext1 = new JavaSparkContext(context);
	Broadcast<String> broadcast = javaSparkContext1.broadcast("hello word");
	
	String value = broadcast.value();
	System.out.println(value);
3、updateStateByKey 算子
  1. 为SparkStreaming中每一个Key维护一份state状态,state类型可以是任意类型的,可以是一个自定义的对象,更新函数也可以是自定义的。
  2. 通过更新函数对该key的状态不断更新,对于每个新的batch而言,SparkStreaming会在使用updateStateByKey的时候为已经存在的key进行state的状态更新。
    比如,某个字符总共出现了几次
  3. 使用到updateStateByKey要开启checkpoint机制和功能 javaStreamingContext.checkpoint("D:/tmp/spark");
JavaPairDStream<String, Integer> sumDS = reudceMap.updateStateByKey(new Function2<List<Integer>, Optional<Integer>, Optional<Integer>>() {
     @Override
     public Optional<Integer> call(List<Integer> integers, Optional<Integer> optional) throws Exception {
         Integer sum = 0;
         if (optional.isPresent()) {
             sum = optional.get();
         }
         for (Integer integer : integers) {
             sum += integer;
         }
         return Optional.of(sum);
     }
 });
4、窗口操作

spark移动计算不移动数据 spark数据流_sparkStreamming_02

  1. 假设每隔5s 1个batch,上图中窗口长度为15s,窗口滑动间隔10s。
  2. 窗口长度和滑动间隔必须是batchInterval的整数倍。如果不是整数倍会检测报错。
// 每隔五秒计算最近15秒的数据
JavaPairDStream<String, Integer> reduceDs = wordsMap.reduceByKeyAndWindow(new Function2<Integer, Integer, Integer>() {
	@Override
	public Integer call(Integer integer, Integer integer2) throws Exception {
	   return integer + integer2;
	}
}, Durations.seconds(15), Durations.seconds(5));

优化之后的

JavaPairDStream<String, Integer> reduceDs = wordsMap.reduceByKeyAndWindow(new Function2<Integer, Integer, Integer>() {
       @Override
        public Integer call(Integer integer, Integer integer2) throws Exception {
            return integer + integer2;
        }
    }, new Function2<Integer, Integer, Integer>() {
        @Override
        public Integer call(Integer integer, Integer integer2) throws Exception {
            return integer - integer2;
        }
    },Durations.seconds(15), Durations.seconds(5));

优化示意图

spark移动计算不移动数据 spark数据流_springstream_03

5、 其他算子

spark移动计算不移动数据 spark数据流_springstream_04

文件操作

spark移动计算不移动数据 spark数据流_spark移动计算不移动数据_05


官方文档 http://spark.apache.org/docs/2.3.2/streaming-programming-guide.html