当前位置:网站首页>Structured Streaming 编程模型(Input Table、Result Table、Output Mode...)
Structured Streaming 编程模型(Input Table、Result Table、Output Mode...)
2022-07-23 23:22:00 【卡卡东~】
最近学习了Spark 的structured Streaming,对此进行总结和分享。
本文转载自 https://blog.csdn.net/wangpei1949/article/details/103948348
阅读前辈写的文章后,觉得对Structured Streaming 编程模型总结的太好了,于是选择转载,后面会加一些个人的补充。
Spark 2.0.0开始,提供了一个用于实时流处理的新组件-Structured Streaming(结构化流)。
本文总结Structured Streaming的编程模型,顺带会总结Structured Streaming与Spark Streaming的区别。
Structured Streaming 编程模型
首先,
Structured Streaming有一个Input Table的概念。即将输入的数据流视为一张Append-Only Input Table表。流式数据源源不断地追加到Input Table表中,每条数据都对应表中的一行。其次,
Structured Streaming有一个Trigger的概念。即多久去检查一次新数据并执行查询。再次,
Structured Streaming有一个Query的概念。即在Input Table上执行各种操作,如map/filter/groupBy/window等等。然后,
Structured Streaming有一个Result Table的概念。即每次Trigger后,会将Query结果更新到Result Table结果表中。最后,
Structured Streaming有一个Output Mode的概念。即每次Trigger后,将Result Table中的哪一部分(Complete(全部)/Append(Append的行)/Update(Update的行))写到外部存储。注意,
Structured Streaming还有一个Checkpoint的概念。通过Checkpoint来跟踪数据源的进度和计算的中间状态,可用于重启或故障后恢复,进而保证计算引擎的EOS语义。
总结,一句话,每次Trigger,会去检查新数据,并追加到Input Table,对Input Table执行Query并更新到Result Table结果表中。最后,按照指定的Output Mode,将结果表中的数据写到外部存储。
以Global WordCount为例,理解Structured Streaming 编程模型。
Structured Streaming与Spark Streaming的区别
再总结下Structured Streaming与Spark Streaming的区别。
- 执行引擎
Spark Streaming是基于RDD构建的,Structured Streaming是基于Spark SQL引擎构建的。
- 编程模型
Spark Streaming在编程模型上是真正的微批。Structured Streaming虽然也有微批模式,但从模型上(Input Table、StreamingQuery、Result Table等等)讲,Structured Streaming更像真正的流。
- RDD与DataFrame、DataSet、SQL
基于Spark Streaming构建流应用,使用的是DStream API(本质上使用的是RDD API),RDD API是Complex, Low-Level的API,同一个流应用,受限于开发者的水平,最终构建出的DAG,运行效率可能差别很大。Structured Streaming应用则是基于Simple,High-Level的API(DataFrame/DataSet/SQL)构建的,受益于Spark SQL引擎的优化,会有更高的性能。
- Processing Time与Event Time
Spark Streaming默认支持的是基于Processing Time(处理时间)的处理,要想在Spark Streaming上实现基于Event Time(事件时间)的处理并解决Late Data(迟到数据)的问题,会非常复杂。Structured Streaming除了支持基于Processing Time(处理时间)的处理外,还提供了基于Event Time(事件时间)的处理,使得这一场景变得很简单。
- End To End的语义保证
Spark Streaming能保证自身是Exactly-Once,但Spark Streaming接入数据和输出到外部存储,往往还需要用户自己去保证,如Spark Streaming接入Kafka数据,一般还需要自己维护Kafka Offset。Structured Streaming结合Checkpoint和支持Replayable的数据源、支持Idempotent的目的地,使得End-To-End Exactly-Once语义保证更加容易。
- Sink
在Spark Streaming中,要输出到外部存储,都需要通过foreachRDD方法来自己编程实现每个批次的数据输出。在Structured Streaming中,默认已经提供了一些Sink,如Console Sink、File Sink、Kafka Sink等,只要通过简单配置,即可使用;如果提供的Sink不满足,实现ForeachWriter/foreachBatch接口,自定义Sink即可。
- 批流统一
现在都在提倡批流统一,在Spark Streaming中,想把流式的DSteam应用转换成批处理的RDD,代价还是很大的。在Structured Streaming中,由于流式应用是基于DataFrame/DataSet/SQL开发的,所以能很容易的转换成批处理。
在上诉的编程模型图中,也许大家看到的Input Table这个输入表会一直增长,那么大数据量肯定不是这样的,需要注意的是,Structured Streaming并不会持久化整个表。它只会从流数据源读取最新的可用数据,以增量方式处理它以更新结果,然后丢弃源数据。它只保留更新结果所需的最小中间状态数据(通过StateStore存储)。
因为笔者通常使用的是java操作spark,以下是使用java语言的一个WordCount:SQL方式:
package com.cjy;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.streaming.StreamingQuery;
import org.apache.spark.sql.streaming.StreamingQueryException;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;
/** * @author cjy * @description: * @date: 2022$ 06/22$ */
public class WordCount2 {
public static void main(String[] args) {
SparkConf sparkConf = new SparkConf().setAppName("sparkSQL").setMaster("local[*]")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.set("spark.io.compression.codec", "snappy")
.set("spark.sql.shuffle.partitions","4"); //shuffle分区小一些
SparkSession sparkSession = SparkSession.builder().config(sparkConf).getOrCreate();
//从数据源中加载数据
Dataset<Row> lines = sparkSession.readStream()
.format("socket")
.option("host", "101.42.165.48")
.option("port", 9999)
.load();
//显示,输出到控制台
//模式:complete、append、update
Dataset<String> flatMap = lines.as(Encoders.STRING()).flatMap((FlatMapFunction<String, String>) word -> {
return Arrays.asList(word.split(" ")).iterator();
}, Encoders.STRING());
flatMap.createOrReplaceTempView("t_words");
String sql = "select value,count(*) as counts" +
" from t_words" +
" group by value" +
" order by counts desc";
Dataset<Row> wordCount = sparkSession.sql(sql);
StreamingQuery result = null;
try {
//输出到控制台,更新模式
result = wordCount.writeStream()
.format("console")
.outputMode("complete")
.start();
result.awaitTermination();
} catch (TimeoutException | StreamingQueryException e) {
e.printStackTrace();
}
sparkSession.stop();
}
}
(函数方式):
package com.cjy;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Encoders;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.streaming.StreamingQuery;
import org.apache.spark.sql.streaming.StreamingQueryException;
import java.util.Arrays;
import java.util.concurrent.TimeoutException;
/** * @author cjy * @description: * @date: 2022$ 06/22$ */
public class WordCount1 {
public static void main(String[] args) {
SparkConf sparkConf = new SparkConf().setAppName("sparkSQL").setMaster("local[*]")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.set("spark.io.compression.codec", "snappy")
.set("spark.sql.shuffle.partitions","4"); //shuffle分区小一些
SparkSession sparkSession = SparkSession.builder().config(sparkConf).getOrCreate();
//从数据源中加载数据
Dataset<Row> lines = sparkSession.readStream()
.format("socket")
.option("host", "101.42.165.48")
.option("port", 9999)
.load();
//显示,输出到控制台
//模式:complete、append、update
try {
Dataset<String> words = lines.as(Encoders.STRING()).flatMap((FlatMapFunction<String, String>) word -> {
return Arrays.asList(word.split(" ")).iterator();
},Encoders.STRING());
Dataset<Row> wordCount = words.groupBy("value").count();
StreamingQuery result = wordCount.writeStream()
.format("console")
//append不支持聚合
//.outputMode("append")
.outputMode("update")
.start();
result.awaitTermination();
} catch (TimeoutException | StreamingQueryException e) {
e.printStackTrace();
}
sparkSession.stop();
}
}
边栏推荐
- BGP routing, MPLS
- Use boundschecker "suggestions collection"
- [laser principle and Application-8]: EMC design of laser circuit
- Raspberry pie SSH login
- Redis管道技术/分区
- 疑似未系安全带 林志颖伤势相对稳定
- 1、 Simplification of digital logic
- anchor free yolov1
- Video Number strengthens the fight against vulgar content: the content that violates public order and good customs must be eliminated
- 1000个Okaleido Tiger首发上线Binance NFT,引发抢购热潮
猜你喜欢

作为开发,你不得不知道的三个性能测试工具|Jmeter、Apipost、JMH使用指南

strncat() strncmp()

FL Studio 20.9 update Chinese version host Daw digital audio workstation

System memory introduction and memory management

Getting started database days3

Sword finger offer II 115. reconstruction sequence

一,数字逻辑的化简

1000 okaleido tiger launched binance NFT, triggering a rush to buy
![[leetcode ladder] the penultimate node in the 022 linked list](/img/72/d3e46a820796a48b458cd2d0a18f8f.png)
[leetcode ladder] the penultimate node in the 022 linked list

浅析基于NVR技术的视频能力与未来发展趋势
随机推荐
The role of physical layer, link layer, network layer, transport layer and application layer of tcp/ip model of internet protocol stack
A great open source micro community light forum source code
System memory introduction and memory management
anchor free yolov1
Grey prediction (matlab)
Exch:pop3 and IMAP4 operation guide
ES6箭頭函數的使用
js把数字转大写
Navicat15 download and installation
Notes on network segment CIDR
Internet协议栈 TCP/IP模型 物理层、链路层、网络层、传输层、应用层的作用
Galaxy Securities opens an account online. Is it safe to open an account on your mobile phone
作为开发,你不得不知道的三个性能测试工具|Jmeter、Apipost、JMH使用指南
Use of pairwise
Getting started database Days1
What is the difference between go run, go build and go install
ES6箭头函数的使用
[leetcode ladder] linked list · 206 reverse linked list
EasyNVR平台如何关闭匿名登录?
The I2C interface mode offline burning operation method of h7-tool has been released (2022-07-16)