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