spark to()_Spark - Structured Streaming

本文学习Spark中的Structured Streaming,参见文档Structured Streaming Programming Guide, kafka-integration。

全文目录

  • Quick Example
  • Programming Model
  • Data Sources
  • Operations on streaming DataFrames/Datasets
  • Starting Streaming Queries
  • Manage Streaming Query
  • Monitoring Streaming query
  • Continuous Processing
  • Integration with Kafka
  • Checkpoint & WAL

Structured Streaming是一款构建于Spark SQL engine之上的可扩展、容错的stream processing engine。我们可以像在static data上执行batch computation一样执行streaming computation。Spark SQL engine负责增长式、持续的执行并在流数据不断到达时更新最终结果。在不同语言中可以用Dataset/DataFrame API来表示streaming aggregations, event-time windows, stream-to-batch joins等,这些操作实际上运行于Spark SQL engine。

Structured Streaming使用checkpointing和Write-Ahead Logs来保证end-to-end exactly-once fault-tolerance guarantees。

默认情况下,Structured Streaming查询使用micro-batch processing engine,使用一系列小的batch jobs来处理data stream,因此能获得100ms的end-to-end latencies以及exactly-once的容错保障。从Spark 2.3开始,引入一种新的low-latency processing模式,Continuous Processing,能够获得1ms的端到端延迟以及at-least-once的容错保障。在不修改查询使用的Dataset/DataFrame operations的情况下,可以根据需要选择模式。

Quick Example

背景:word count of text data received from a data server listening on a TCP socket

下面是相关的Scala代码。lines表示包含streaming text data的unbounded table,表中包含一个名为value的column。在设置好query之后,便可以开始接收数据。awaitTermination()防止query时停止。

import 

上面的代码可以通过创建Spark Application来执行。也可以运行Spark Example。

$ ./bin/run-example org.apache.spark.examples.sql.streaming.StructuredNetworkWordCount localhost 9999

但在执行之前需要先启动生成流数据的server。这里使用Netcat来作为server,启动之后,所有在console中输入的字符都会被放入流中。

$ nc -lk 9999
$ apache spark
$ apache hadoop
+------+-----+
| value|count|
+------+-----+
|apache|    2|
| spark|    1|
|hadoop|    1|
+------+-----+

Programming Model

Structured Streaming的关键思想就是将live data stream当作会持续append数据的table,这样就可以将stream processing model类似于batch processing model。

aca47ea168e5e80e5ddb64e495d0fef4.png

df462ae2c9e560fdf726ecde1e9aecdb.png

对于输入的query将会生成result table,每个trigger interval,新行添加进input table并最终更新result table。

Output mode分为3类:

  • Complete Mode将更新后的完整result table写入外部存储;
  • Append Mode 只将上次更新后append到result table的新行写入外部存储,只适用于result table中已存在row不会被影响的情况;
  • Update Mode 只将上次更新后result table中被更新的行写入外部存储,该模式在2.1.1版本后才存在;

下图是example的处理过程,使用complete mode.

3f95bbc8b471deface7fc583725a7750.png

注意:Structured streaming并不存储完整的table,只是读取最新的数据来动态更新结果,只会保留少量的中间结果来获得最终结果。

这种模式和其他的stream processing engine差别很大。很多streaming system需要用户自己执行aggregation,需要处理容错和数据一致性。这种模式下,Spark代替用户来更新result table。该模式使用数据中的event time(数据生成的时间)组成time window作为一组进行处理,这样data stream就可以像static dataset一样处理。而且,这种模式天然可以处理late data(获取时间比预期晚的数据),Spark 2.1之后支持watermarking指定late data的阈值,从而允许engine适当清理old state。

Structured streaming设计的关键目标是实现end-to-end exactly-once semantics。为了实现这个目标,要求stream source具有offsets来记录读取的位置,类似于kafka offset。Engine使用checkpointing和write-ahead logs来记录每批次处理数据的offset range。

Data Sources

Spark 2.0之后,DataFrames和Datasets可以同时表示static、bounded的数据以及streaming、unbounded的数据,并使用相同的操作来处理。

Streaming DataFrames可以通过SparkSession.readStream()来创建,返回值实现DataStreamReader接口,可以指定source的详情,包括data format, schema, options。

下面是几种built-in的input sources,用来生成Streaming DataFrames.

  • File source 将文件内容作为stream的来源,支持文件格式包括text, csv, json, orc, parquet,参数包括path,maxFilesPerTrigger,latestFirst,fileNameOnly,参见接口DataStreamReader来查看详细信息;默认情况下,使用文件修改时间顺序来读取文件,当指定latestFirst时,顺序逆转。
  • Kafka source 从kafka读取数据,兼容Kafka broker versions 0.10.0以及更高,参见 Kafka Integration Guide;
  • Socket source (for testing) 从socket connection中读取UTF8 text data,listening server socket处于driver上, 参数包括host, port。注意:该类型只用于测试,并不提供端到端的容错保障;
  • Rate source (for testing) 每分钟生成指定行数的数据,每行数据包括时间和值,值记录message的数量, 参数包括rowsPerSecond,rampUpTime,numPartitions;

下面是读取csv格式数据的示例。默认情况下,Structured Streaming使用file作为source需要指定schema。

// Read all the csv files written atomically in a directory

Operations on streaming DataFrames/Datasets

大多数在DataFrame/Dataset上的操作都在streaming中支持。

-Basic operation

case 

-Windows operation

Structured streaming模式能够自动处理late data,但由于不能一直保留所有中间状态,Spark 2.1引入watermarking来自动清理old state。对于特定windows,其ending time为T,设置的阈值为late threshold, 当前看到的最大event time Max, 满足关系 Max-threshold>T就可以清理对应windows的状态。

下面示例中,我们使用column timestamp来创建watermark和window。当output mode为update时,超出window的数据不被更新。

import 

a004425b66c268c67d0feccc96c17016.png

使用watermark的条件:

  • output mode必须是update或append,不能时complete;
  • aggregation必须有event-time column或event-time column上的window;
  • withWatermark使用的column必须与aggregation使用的column相同,并且withWatermark必须在aggregation之前调用;

注意:watermark能够保证范围内的数据不被删除,但不能保证范围外的数据一定被删除,这样范围外的数据也可能被用于aggregation。

-Join operation

Structured Streaming支持streaming Dataset/DataFrame之间的join以及其与static Dataset/DataFrame之间的join。

下面是Streaming和Static之间的join示例。这种join是无状态的,而且有些类型的outer join目前还不支持。

val 

Spark 2.3引入stream-stream join,难点是任何时候join的两边的数据都是不完整的,导致输入之间很难找到match。这种可以通过缓存两边的old data并结合watermark来处理。之间的join可以使用time range join condition(JOIN ON leftTime BETWEEN rightTime AND rightTime + INTERVAL 1 HOUR) 或 event-time windows (JOIN ON leftTimeWindow = rightTimeWindow). 对于inner join可以不指定watermark和约束,但是outer join必须指定,因为它想要生成join时的null。

// Apply watermarks on event-time columns

Join是可以传递的,如df1.join(df2, ...).join(df3, ...).join(df4, ....);Spark 2.4中只能在Append output mode中使用join,其他输出模式下不支持,且在join之前不能使用non-map like操作。

  • 去重

流去重可以使用watermark,也可以不使用。

val 

有些操作不适用于stream DataFrame/Dataset,如:多个streaming aggregations,获取前N个数据,distinct操作,排序操作也只能在aggregation之后且为complete output mode,有些outer join操作也不支持。有些查询之后需要立即返回结果的操作也不被支持。

Starting Streaming Queries

在定义好stream DataFrame/Dataset之后,便可以开始执行streaming computation,需要使用Dataset.writeStream()返回的DataStreamWriter。

在接口中需要指定下面配置:

  1. output sink的细节,如格式,location等;
  2. output mode,指定写入output sink的内容;
  3. query name, query的唯一识别名称;
  4. trigger internal,若不指定,系统会在上波数据处理完后获取下一波数据,当trigger time因为上次处理超时错过后,系统会立即触发;
  5. checkpoint location, 指定系统写checkpoint info的位置,通常为目录。

-output mode

  • Append mode (default) : 上次trigger后只有添加进result table的新行写入sink,适用于result table中的数据不会被改动的情况,能够保证每行只被输出一次;
  • Complete mode : 在每次trigger后,将整个result table输出到sink,被aggregation操作支持;
  • Updated mode: 上次trigger后,result table中被更新的行输出到sink,在Spark 2.1.1后被支持;

-output sinks

有一些built-in的sink,其中console和memory类型用于debug。必须调用start()函数来启动query的执行。

// file sink, store output to a dir

下面列举各种sink的属性。

38e0f8faca121062574064562579292c.png

foreach和foreachBatch允许在streaming的output上执行任意操作,区别时foreach作用于每一个row,而foreachBatch作用于每一个micro-batch。

foreachBatch的输入为Dataset或DataFrame某一个micro-batch的数据batchDF以及batch id。可以用来重新处理每个微批,可以将流数据存放在多个位置,可以在流数据上执行额外的操作。默认情况下,foreachBatch只提供at-least-once的容错保证,但可以通过batchId实现exactly-once。同时,foreachBatch由于使用micro-batch execution的特性,不支持continuous processing mode。

下面是存储多个位置的示例。

streamingDF

-Trigger

Streaming query的trigger设置定义了流数据处理的实时性,表明StreamingQuery生成结果的频率,是micro-batch query还是continuous query。

  • 默认是micro-batch query,当上一批次处理完就处理下一批次;
  • Fixed interval micro-batches 若设置固定internal,则周期性处理数据,没处理完数据延迟执行,没有新数据则不执行;
  • one-time micro-batch 只处理一个batch就终止query,在很多场景下比较节省时间;
  • continuous mode 为低延时,持续处理数据,在指定的interval执行异步checkpointing。
import 

Manage Streaming Query

Streaming query被启动后会创建StreamingQuery,可以用来管理和监控query。

val 

可以在一个SparkSession上启动任意多个query,这些query并行执行并共享集群资源。可以使用sparkSession.streams()来获取StreamingQueryManager,来管理当前active的query。

val 

Monitoring Streaming query

有多重方式可以监控active streaming queries,可以使用Spark's Dropwizard Metrics支持来将metrics push到外部系统,也可以编程获取。

可以直接调用streamingQuery.lastProgress(),streamingQuery.status().lastProgress() 来获得StreamingQueryProgress对象,其中包含stream中上一个trigger的所有信息,包括处理的数据,速度,延迟等信息。streamingQuery.recentProgress返回最近几个process组成的数组。streamingQuery.status()返回StreamingQueryStatus,指示立即执行什么query。

val 
  • 使用异步API来report metrics

下面的示例将监控SparkSession下的所有query,当query启动、停止或处理时都会打印信息。

val 
  • 使用Dropwizard来report metrics

Spark支持使用Dropwizard Library来report metric,必须显式配置spark.sql.streaming.metricsEnabled为true。

spark.conf.set("spark.sql.streaming.metricsEnabled", "true")
// or
spark.sql("SET spark.sql.streaming.metricsEnabled=true")

当配置被设置后,report metrics将由Dropwizard输出到sinks,像Ganglia, Graphite, JMX, etc。

使用checkpointing和write-ahead logs,能够在出现failure或强制停掉时恢复之前的状态并继续执行。这通过设置checkpoint location来实现,query将保存process的所有信息。checkpoint location必须是HDFS文件系统兼容的路径。

aggDF
  

Continuous Processing

Continuous Processing是Spark 2.3引入的实验式的streaming执行模式,提供端到端的低延时(~1ms)以及至少一次的容错保障。而默认的micro-batch执行模式提供exactly-once的容错保障但最好延时~100ms。

在continuous processing mode下执行query只需要指定continuous trigger

import 

在spark 2.4中只有下面的操作被continuous processing mode支持:

  • Operations只支持map-like Dataset/DataFrame operations,即projections (select,map,flatMap,mapPartitions, etc.) and selections (where,filter, etc.)
  • Sources Kafka source支持所有的option
  • Sinks Kafka sink支持所有option;Memory sink和Console sink用于debug。

Integration with Kafka

使用Kafka需要引入如下依赖。

groupId = org.apache.spark
artifactId = spark-sql-kafka-0-10_2.12
version = 2.4.5

-Read from kafka

出现failure或强制停掉时恢复之前的状态并继续执行。这通过设置checkpoint location来实现,query将保存process的所有信息。checkpoint location必须HDFS文件系统兼容的路径。

// Read through streaming query

上面的示例中都只监听一个topic,可以监听多个topics。

// subscribe to multiple topics

同时,batch query时指定query offset.

.

source中的每一行包含下面信息。

b58f8d7acb191de9d5dde8ef9cd3941f.png

-Write to kafka

Kafka支持at-least once的写语义,当有些数据被实际记录但没有acknowledge时会出现重复数据,因此有可能存在重复的记录。或许可以使用unique的primary key id来解决这个问题。

写数据到Kafka,包含下面的数据,只有value是必选的,若key不提供,传入null。若配置中设置了topic,将覆盖这里的topic,因此topic也可以省略。当创建Kafka sink时,必须指定kafka.bootstrap.servers。

6a0e9cd7fa6dd0919654cbd6712b8a12.png
-- 

Checkpoint & WAL

为避免内存缓存数据不丢失,引入Checkpoint和Write-ahead log机制来错误恢复。

Checkpoint分为Metadata checkpoint和data checkpoint,前者用于driver挂掉后恢复Streaming context,后者用于处理stateful streaming operation,即后续操作依赖之前的数据。

WAL先将数据存放在日志文件中,然后再对数据进行操作,因此,可以在系统挂掉后,通过日志文件进行错误恢复。像kafka这种具有确认机制的数据源,只有数据写入到WAL后,才向kafka发送确认消息。

启用WAL需要如下配置:

  1. 为StreamingQuery设置checkpoint目录,用于保存WAL;
  2. 开启WAL机制,设置spark.streaming.receiver.writeAheadLog.enable为true;

WAL缺点:

  1. 减少Receiver的吞吐量;
  2. 数据重复处理;

Checkpoint与cache的区别:cache将数据缓存在内存或磁盘,在rdd操作过程中保存,RDD之间的关系还存在;而checkpoint存放在高容错性的HDFS中,在RDD操作执行结束时保存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值