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 算子
- 爲SparkStreaming中每一個Key維護一份state狀態,state類型可以是任意類型的,可以是一個自定義的對象,更新函數也可以是自定義的。
- 通過更新函數對該key的狀態不斷更新,對於每個新的batch而言,SparkStreaming會在使用updateStateByKey的時候爲已經存在的key進行state的狀態更新。
比如,某個字符總共出現了幾次 - 使用到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、窗口操作
- 假設每隔5s 1個batch,上圖中窗口長度爲15s,窗口滑動間隔10s。
- 窗口長度和滑動間隔必須是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