微批处理是 Structured Streaming 默认的处理模型。
微批处理 (Micro-batching):
优点:
缺点:
持续处理是 Structured Streaming 在 Spark 2.3 版本中引入的实验性功能。在这种模型中,实时数据流被视为连续的记录流,Spark 引擎以较低的延迟(毫秒级)持续处理每条记录。
持续处理 (Continuous Processing):
优点:
缺点:
这两种模型可以用以下表格进行比较:
特性 | 微批处理 | 持续处理 |
---|---|---|
处理延迟 | 秒级 | 毫秒级 |
容错性 | 高 | 中到高 |
API一致性 | 与批处理一致 | 与批处理一致 |
成熟度 | 高 | 低 |
吞吐量 | 高 | 高 |
复杂性 | 低 | 高 |
状态管理 | 容易 | 较复杂 |
与其他Spark组件集成 | 无缝 | 无缝 |
在选择模型时,需要根据具体的应用场景、延迟要求和资源情况来决定使用哪种模型。如果应用可以容忍秒级的延迟,微批处理是一个成熟且简单的选择。如果应用需要极低的延迟,可以尝试使用持续处理模型。
微批处理模型中,“写日志”通常是指在处理批次之前记录其信息以便于故障恢复。而在持续处理模型中,“写日志”可能更多地关联于实时记录每个事件或数据项的处理状态。
导入pyspark模块
from pyspark.sql import SparkSession
from pyspark.sql.functions import explode
from pyspark.sql.functions import split
#如果直接使用pyspark交互就不需要导入,但是如果是自己编写python就需要导入模块
创建SparkSession对象:
SparkSession
对象。这是Structured Streaming编程的入口点。from pyspark.sql import SparkSession
spark = SparkSession \
.builder \
.appName("Structured Streaming App") \
.getOrCreate()
spark.sparkContext.setLogLevel("warn")
稍微讲解一下appName得是被唯一标识的,spark.sparkContext.setLogLevel(“warn”)是设置日志显示级别,无关紧要的就不输出
定义输入源:
df = spark \
.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "host1:port1,host2:port2") \
.option("subscribe", "topic1") \
.load()
定义转换:
from pyspark.sql.functions import col, window
words = df.selectExpr("CAST(value AS STRING)")
wordCounts = words.groupBy(
window(col("timestamp"), "10 minutes", "5 minutes"),
col("word")
).count()
定义输出接收器:
query = wordCounts \
.writeStream \
.outputMode("complete") \
.format("console") \
.start()
启动流处理:
query.awaitTermination()
监控和异常处理:
try:
query.awaitTermination()
except KeyboardInterrupt:
query.stop()
Structured Streaming中的文件源允许你监视指定目录中的新文件,并从中读取数据。这里是一些常见的选项:
true
会首先处理最新的文件,这可能对某些实时性要求较高的应用程序有用。json
、csv
、parquet
等。# 创建一个DataFrame表示从目录`/path/to/directory`中连续读取的数据
csvDF = spark \
.readStream \
.option("sep", ",") \
.schema(userSchema) \ # 可以定义一个schema
.csv("/path/to/directory")
# 启动流查询,输出模式为追加模式,并将结果输出到控制台
query = csvDF.writeStream \
.outputMode("append") \
.format("console") \
.start()
query.awaitTermination()
在这个例子中,我们首先使用readStream
来创建一个DataFrame读取流。我们通过.option("sep", ",")
指定了CSV值之间的分隔符为逗号。schema(userSchema)
部分定义了CSV文件的结构,你需要在代码中提前定义userSchema
。
然后,我们指定了监视的目录路径。csv("/path/to/directory")
表示我们希望读取的文件类型是CSV。
最后,我们定义了一个查询,该查询将输出模式设置为append
,这意味着仅将新的数据行附加到结果中。我们使用.format("console")
将输出结果发送到控制台,这对于调试和开发是很有用的。start()
方法启动流查询,而awaitTermination()
方法则是让应用程序等待流处理的终止,以进行长时间运行。
在Structured Streaming中,Kafka源允许你从Kafka主题读取数据流。这里是一些常见的Kafka源选项:
true
。下面是一个Kafka源的操作示例,它从Kafka主题读取数据流,并将其加载为DataFrame:
# 创建一个DataFrame表示从名为"updates"的Kafka主题读取的数据
kafkaDF = spark \
.readStream \
.format("kafka") \
.option("kafka.bootstrap.servers", "host1:port1,host2:port2") \
.option("subscribe", "updates") \
.option("startingOffsets", "latest") \
.load()
# 选择我们需要的字段并将value字段从字节转换为字符串
selectedDF = kafkaDF.selectExpr("CAST(key AS STRING)", "CAST(value AS STRING)")
# 启动流查询,将结果输出到控制台
query = selectedDF.writeStream \
.outputMode("append") \
.format("console") \
.start()
query.awaitTermination()
在这个例子中,我们使用.format("kafka")
来告诉Spark我们正在使用Kafka源,并通过option
来设置Kafka的相关参数。.load()
方法加载Kafka主题为DataFrame。
以下是.option()
方法设置的参数的解释:
host
和port
分别对应Kafka服务器的IP地址和监听端口。selectExpr
是一个转换操作,它允许你运行SQL表达式。在这里,我们将key
和value
列从字节转换为字符串类型,便于阅读和处理。
查询的其余部分和之前的例子类似,这次我们也是以追加模式输出到控制台,并启动流查询。
请注意,你需要有一个运行中的Kafka集群,并已经创建了相关的主题,以及在Spark集群上配置了适当的Kafka依赖。
在Structured Streaming中,使用socket源意味着数据流将来自于一个TCP套接字连接。这是最简单的流式数据源之一,通常用于测试和原型设计阶段。它允许您从通过TCP连接发送的数据流中读取文本数据。
以下是如何在Structured Streaming中设置socket源:
from pyspark.sql import SparkSession
# 初始化SparkSession
spark = SparkSession.builder \
.appName("StructuredSocketRead") \
.getOrCreate()
# 创建流式DataFrame,连接到指定的socket
lines = spark.readStream \
.format("socket") \
.option("host", "localhost") \
.option("port", 9999) \
.load()
# 使用DataFrame API进行数据处理
# ...
# 启动流查询
query = lines.writeStream \
.outputMode("append") \
.format("console") \
.start()
query.awaitTermination()
上面的代码片段执行了以下操作:
SparkSession.builder
初始化了一个SparkSession。readStream
方法创建了一个流式DataFrame,它将会连接到在localhost
上的9999
端口监听的TCP套接字。format("socket")
指定了数据源格式为socket。.option("host", "localhost")
和.option("port", 9999)
设置了监听的主机地址和端口号。.load()
方法触发了对socket源的连接。lines
DataFrame上应用各种转换操作,如过滤、选择、聚合等。writeStream
定义了如何输出处理后的流数据,这里通过.format("console")
指定了输出到控制台。.start()
开始接收数据并处理,.awaitTermination()
方法让程序持续运行,直到手动停止或者遇到错误。使用socket源进行Structured Streaming是一个好方法,可以实时测试您的流处理逻辑,因为您可以很容易地通过如netcat
之类的工具来发送数据。
然后在另外一个打开虚拟机另外窗口输入
nc -lk 你的端口号
在Structured Streaming中,rate
源每秒生成特定的数据行,两个列的数据流:timestamp
和value
。这个源非常适合生成简单的数据流进行测试和调试。
每个输出行包含一个timestamp
和value
。timestamp
是每个触发器触发时的当前时间戳,而value
是从程序开始以来的触发器触发的次数。
下面是如何在Structured Streaming中设置rate
源的例子:
from pyspark.sql import SparkSession
# 初始化SparkSession
spark = SparkSession.builder \
.appName("StructuredRateRead") \
.getOrCreate()
# 创建流式DataFrame,用rate源
df = spark.readStream \
.format("rate") \
.option("rowsPerSecond", "1") \
.load()
# 使用DataFrame API进行数据处理
# ...
# 启动流查询,输出到控制台
query = df.writeStream \
.outputMode("append") \
.format("console") \
.start()
query.awaitTermination()
上面的代码片段执行了以下操作:
SparkSession.builder
初始化了一个SparkSession。readStream
方法创建了一个流式DataFrame,它将会使用rate
源。.option("rowsPerSecond", "1")
设置每秒生成的行数。.load()
方法触发了对rate源的连接。.writeStream
定义了如何输出处理后的流数据。.format("console")
指定了输出到控制台。.start()
开始接收数据并处理,.awaitTermination()
方法让程序持续运行,直到手动停止或者遇到错误。rate
源非常适合开发和测试时生成连续的、预测的数据流,但它不适用于生产环境,因为它不是从实际的数据源读取数据。
可以使用option
方法来配置这个源的行为。以下是rate
源的一些常见选项和它们的功能:
rowsPerSecond:指定每秒生成的行数。这个选项可以帮助你控制数据生成的速率。
示例:.option("rowsPerSecond", "10")
表示每秒生成10行数据。
rampUpTime:在指定时间内逐渐增加到rowsPerSecond
指定的速率。这通常用于模拟数据源在启动时从没有数据到达指定速率的过渡过程。
示例:.option("rampUpTime", "1m")
在1分钟内逐渐增加生成的数据行数。
numPartitions:指定生成的数据将在多少个分区中分布。这可以帮助模拟并行数据流的情况。
示例:.option("numPartitions", "2")
表示数据将分布在两个分区中。
使用这些选项的例子:
df = spark.readStream \
.format("rate") \
.option("rowsPerSecond", "100") \
.option("rampUpTime", "5s") \
.option("numPartitions", "2") \
.load()
这将会创建一个数据流,初始时每秒100行数据,5秒内逐渐增加到这个速率,并且数据在两个分区中分布。
Structured Streaming中的输出接收器(Sink)是指数据流最终输出到的地方。Spark Structured Streaming提供了多种不同的输出接收器,以支持将数据流输出到各种外部系统和格式。以下是一些常见的输出接收器:
文件接收器(File Sink):输出数据到文件系统。支持的格式包括文本、JSON、CSV、Parquet等。可以指定文件输出目录和文件格式。
Kafka接收器(Kafka Sink):输出数据到Kafka主题。可以指定Kafka服务器的地址和要写入的主题。
控制台接收器(Console Sink):将数据输出到控制台,主要用于调试和开发。
内存接收器(Memory Sink):输出数据到内存表中,允许在内存中查询数据。这主要用于快速测试和原型开发。
Foreach接收器:提供了一个通用接口,允许你对数据流中的每个记录执行任意操作。这可以用于实现自定义的输出逻辑,例如写入自定义外部存储或调用外部API。
使用Structured Streaming的输出接收器时,你需要指定输出模式(如"append"、“complete"或"update”),输出接收器类型(如"console"、“kafka”、"file"等),以及任何必要的配置选项。
例如,将数据流输出到控制台的代码示例:
query = df.writeStream \
.outputMode("append") \
.format("console") \
.start()
将数据流输出到Kafka的代码示例:
query = df.writeStream \
.outputMode("update") \
.format("kafka") \
.option("kafka.bootstrap.servers", "host1:port1,host2:port2") \
.option("topic", "updates") \
.start()
这些代码示例展示了如何将数据流输出到不同类型的接收器。每种类型的接收器可能有不同的配置选项和限制,所以在使用时需要查阅具体的文档。