当前位置:网站首页>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();
}
}
边栏推荐
- Analysis of mobile semantics and perfect forwarding
- js把数字转大写
- The role of physical layer, link layer, network layer, transport layer and application layer of tcp/ip model of internet protocol stack
- 【Unity3D日常BUG】Unity3D解决“找不到类型或命名空间名称“XXX”(您是否缺少using指令或程序集引用?)”等问题
- 系列文章|云原生时代下微服务架构进阶之路 - 微服务拆分的最佳实践
- Leetcode: palindrome number
- SOLIDWORK learning notes: Sketch geometric relationships and editing
- Galaxy Securities opens an account online. Is it safe to open an account on your mobile phone
- Upgrade unity visual studio 2019 to 2022 (throw away pirated red slag)
- Go language multiple return values and return error types
猜你喜欢

js把数字转大写

fl studio 20.9更新中文版宿主DAW数字音频工作站

YOLOv4: Optimal Speed and Accuracy of Object Detection

BGP基础实验

Classification model - logistic regression, Fisher linear discriminant (SPSS)

After reading this article, thoroughly understand grpc!

EasyNVR平台如何关闭匿名登录?

Redis管道技术/分区

在openEuler社区开源的Embedded SIG,来聊聊它的多 OS 混合部署框架

PHP(2)
随机推荐
Interface test
Brief analysis of compiling principle of.Net CLR R2R
mysqlbinlog命令介绍(远程拉取binlog日志)
YOLOv4: Optimal Speed and Accuracy of Object Detection
Sword finger offer II 115. reconstruction sequence
How to reasonably estimate the size of thread pool
[leetcode ladder] linked list · 203 remove linked list elements
Ways to improve the utilization of openeuler resources 01: Introduction
【音视频技术】视频质量评价 MSU VQMT & Netflix vmaf
Remember an experience of being cheated by the Internet
PHP(2)
史上最全的2022年版Android面试题
D1-h development board - Introduction to Nezha development
Exch:pop3 and IMAP4 operation guide
Niuke C basic exercises
一,数字逻辑的化简
(CVPR-2022)BiCnet
Debian | Can’t locate Debian/Debhelper/Sequence/germinate. pm in @INC
None和nan、NaN、NAN
FL Studio 20.9 update Chinese version host Daw digital audio workstation