Spark2.x學習筆記(三) - Spark Streaming

SparkStreaming簡介

SparkStreaming是流式處理框架,是Spark API的擴展,支持可擴展、高吞吐量、容錯的實時數據流處理,實時數據的來源可以是:Kafka, Flume, Twitter, ZeroMQ或者TCP sockets,並且可以使用高級功能的複雜算子來處理流數據。例如:map,reduce,join,window 。最終,處理後的數據可以存放在文件系統,數據庫等,方便實時展現。
在這裏插入圖片描述

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、窗口操作

在這裏插入圖片描述

  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));

優化示意圖
在這裏插入圖片描述

5、 其他算子

在這裏插入圖片描述

文件操作
在這裏插入圖片描述
官方文檔 http://spark.apache.org/docs/2.3.2/streaming-programming-guide.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章