1、概览
结构化流是一个构建在 Spark SQL 引擎上的可伸缩和容错的流处理引擎。您可以像对静态数据表示批处理计算一样表示流计算。Spark SQL 引擎将负责以增量方式持续运行它,并在流数据继续到达时更新最终结果。您可以使用 Scala、 Java、 Python 或 r 中的 Dataset/dataframeapi 来表达流聚合、事件时间窗口、流到批处理连接等。计算在同一个经过优化的Spark SQL引擎上执行。最后,系统通过检查点和WAL日志确保端到端一次性的容错保证。简而言之,结构化流提供了快速、可伸缩、容错、端到端的一次性流处理,用户无需对流进行考虑。
在内部,默认情况下,结构化 Streaming 查询使用微批处理引擎进行处理,该引擎将数据流作为一系列小批处理作业进行处理,从而实现低至100毫秒的端到端延迟,并保证一次性的容错。但是,自从 Spark 2.3之后,我们引入了一种新的低延迟处理模式,称为连续处理(Continuous Processing) ,它可以在至少一次保证的情况下实现低至1毫秒的端到端延迟。在不更改查询中的 Dataset/DataFrame 操作的情况下,您将能够根据应用程序需求选择模式。
在本指南中,我们将向您介绍编程模型和 api。我们将主要使用默认的微批处理模型来解释这些概念,然后再讨论连续处理模型。首先,让我们从一个结构化流查询的简单例子开始——流式单词计数。
2、示例
假设您希望维护从侦听 TCP 套接字的数据服务器接收的文本数据的运行字数。让我们看看如何使用结构化流来表示这一点。你可以在 Scala/Java/Python/r 中看到完整的代码,如果你下载了 Spark,你可以直接运行这个例子。无论如何,让我们一步一步地学习这个示例并理解它是如何工作的。首先,我们必须导入必要的类并创建一个本地 SparkSession,这是所有与 Spark 相关的功能的起点。
import org.apache.spark.sql.functions._
import org.apache.spark.sql.SparkSession
val spark = SparkSession
.builder
.appName("StructuredNetworkWordCount")
.getOrCreate()
import spark.implicits._
接下来,让我们创建一个流式 DataFrame,它表示从侦听 localhost: 9999的服务器接收的文本数据,并将 DataFrame 转换为计算单词数。
// Create DataFrame representing the stream of input lines from connection to localhost:9999
val lines = spark.readStream
.format("socket")
.option("host", "localhost")
.option("port", 9999)
.load()
// Split the lines into words
val words = lines.as[String].flatMap(_.split(" "))
// Generate running word count
val wordCounts = words.groupBy("value").count()
这个dataFrame类型的lines表示一个包含流文本数据的无界表。此表包含一列名为“ value”的字符串,流文本数据中的每一行都成为表中的一行。注意,由于我们正在设置转换,而且还没有开始,因此当前没有接收到任何数据。接下来,我们使用命令.as[String]将 DataFrame 转换为String类型的DataSet,这样我们就可以应用flatMap操作将每一行分成多个单词。Dataset 类型的words包含所有单词。最后,我们通过对 Dataset 中的唯一值进行分组并计数来定义 wordCounts DataFrame。请注意,这是一个流式 datafarme,它表示流的运行字计数。
我们现在已经设置了对流数据的查询。剩下的就是实际上开始接收数据和计算计数。为此,我们将其设置为在每次更新时将完整的计数集(由 outputMode (“ complete”)指定)打印到控制台。然后使用 start ()启动流式计算。
// Start running the query that prints the running counts to the console
val query = wordCounts.writeStream
.outputMode("complete")
.format("console")
.start()
query.awaitTermination()
在执行此代码之后,流式计算将在后台启动。查询对象是活动流查询的句柄,我们已经决定使用 awaitTermination ()等待查询的终止,以防止在查询处于活动状态时进程退出。
要实际执行此示例代码,您可以在自己的 Spark 应用程序中编译代码,或者在下载了 Spark 之后简单地运行此示例。我们展示的是后者。首先需要使用以下命令将 Netcat (大多数类 unix 系统中的一个小实用程序)作为数据服务器运行
$ nc -lk 9999
然后,在另一个终端中,您可以使用
$ ./bin/run-example org.apache.spark.examples.sql.streaming.StructuredNetworkWordCount localhost 9999
然后,在运行 netcat 服务器的终端中键入的任何行都将被计数并每秒钟在屏幕上打印一次。它看起来像下面这样。