Spark The Definitive Guide(Spark权威指南) 中文版。本书详细介绍了Spark2.x版本的各个模块,目前市面上最好的Spark2.x学习书籍!!!
扫码关注公众号:登峰大数据,阅读中文Spark权威指南(完整版),系统学习Spark大数据框架!
如果您觉得作者翻译的内容有帮助,请分享给更多人。您的分享,是作者翻译的动力
既然我们已经简要概述了流处理,现在让我们直接进入结构化流。在本章中,我们将再次说明结构化流背后的一些关键概念,然后将它们与一些代码示例一起应用,这些代码示例展示了系统的易用性。
21.1.Structured Streaming(结构化流)基础知识
正如我们在第20章末尾所讨论的,结构化流是构建在Spark SQL引擎上的流处理框架。结构化流使用Spark中现有的结构化API (DataFrames、dataset和SQL),而不是引入单独的API,这意味着支持您熟悉的所有操作。用户表达流计算的方式与在静态数据上编写批处理计算的方式相同。在指定这一点并指定流目的地之后,结构化流引擎将负责在新数据到达系统时以增量和连续的方式运行查询。然后使用本书第二部分中讨论的相同Catalyst引擎执行这些计算逻辑指令,包括查询优化、代码生成等。除了核心的结构化处理引擎之外,结构化流还包括许多专门用于流的特性。例如,结构化流通过检查点和write-ahead logs确保端到端、精确的一次处理以及容错。
结构化流背后的主要思想是将数据流视为一个表,数据不断地附加到该表中。然后,作业定期检查新的输入数据,对其进行处理,在需要时更新状态存储中的一些内部状态,并更新其结果。该API的一个基础是,在进行批处理或流处理时,您不应该更改查询的代码——您应该只指定是以批处理方式还是流方式运行该查询。在内部,结构化流将自动指出如何“增量化”您的查询,即在新数据到达时有效地更新其结果,并以容错方式运行它。
简单地说,结构化流是“您的DataFrame,且是流式的”。这使得开始使用流处理应用程序变得非常容易。您可能已经有了它们的代码! 然而,结构化流能够运行的查询类型有一些限制,还有一些您必须考虑的特定于流的新概念,如事件时间和无序数据。我们将在本章和接下来的章节中讨论这些问题。最后,通过与Spark的其余部分集成,结构化流使用户能够构建我们称为连续应用程序的应用程序。continous应用程序是一个端到端应用程序,它通过组合各种工具实时响应数据:流作业、批处理作业、流和离线数据之间的连接以及交互式查询。因为现在大多数流作业都是在一个更大的连续应用程序上下文中部署的,所以Spark开发人员希望能够更容易地在一个框架中指定整个应用程序,并在不同的部分中获得一致的结果。例如,您可以使用结构化流连续更新一个表,用户可以使用Spark SQL交互式地查询该表,为Mllib训练的机器学习模型提供服务,或者在Spark的任何数据源中使用离线数据连接流。
21.2.重要概念
既然我们已经说到了高级概念,现在让我们介绍结构化流作业中的一些重要概念。你会发现,没有很多重要概念。这是因为结构化流被设计得很简单。阅读一些其他的大数据流书籍,你会注意到他们开始介绍术语,比如用于倾斜数据reducers的分布式流处理拓扑(一种夸张但准确的描述)和其他复杂的术语。Spark的目标是自动处理这些问题,并为用户提供在流上运行任何Spark计算的简单方法。
21.2.1.Transformations 和 Actions
结构化流使用了我们在本书中看到的相同的Transformations和Actions概念。结构化流中可用的Transformations与我们在第二部分中看到的Transformations完全相同,但有一些限制。这些限制通常涉及引擎还不能支持的某些类型的查询,尽管一些限制已经在Spark的新版本中被取消了。在结构化流中通常只有一个action可用于启动流,然后流将连续运行并输出结果。
21.2.2.Input Sources
结构化流支持以流方式读取的多个输入源。从Spark 2.2开始,支持的输入源如下:
Apache Kafka 0.10
分布式文件系统上的文件,如HDFS或S3 (Spark将不断读取目录中的新文件)
用于测试的socket
我们将在本章后面深入讨论这些,但值得一提的是,Spark的作者正在开发一个稳定的源API,以便您可以构建自己的流连接器。
21.2.3.Sinks
就像源允许您将数据放入结构化流中一样,sink指定流的结果集的目标。接收器和执行引擎还负责可靠地跟踪数据处理的确切进度。以下是Spark 2.2支持的输出接收器:
Apache Kafka 0.10
几乎任何文件格式
用于在输出记录上运行任意计算的foreach接收器
用于测试的控制台接收器console sink
用于调试的内存接收器 memory sink
我们将在本章后面讨论Sources时更详细地讨论这些。
21.2.4.Output Modes
为我们的结构化流工作定义一个接收器只是故事的一半。我们还需要定义我们希望Spark如何向该接收器写入数据。例如,我们是否只想添加新信息?随着时间的推移,我们是否希望随着接收到关于行的更多信息而更新行(例如,更新给定web页面的点击计数)?我们是否希望每次都完全覆盖结果集(即始终为所有页面编写具有完整点击计数的文件)? 为此,我们定义了一个输出模式,类似于我们在静态结构化api中定义输出模式的方式。
支持的输出模式如下:
Append (只向输出接收器添加新记录)
Update (更新已更改的记录)
Complete (重写完整输出)
一个重要的细节是,某些查询和某些接收器只支持特定的输出模式,我们将在本书的后面讨论。例如,假设您的工作只是在流上执行map。当新记录到达时,输出数据将无限增长,因此使用Complete模式没有意义,因为Complete模式要求立即将所有数据写入一个新文件。相反,如果您要做一个聚合到有限数量的键中,那么Complete和Update模式是有意义的,但是Append没有意义,因为有些键的值需要随着时间的推移而更新。
21.2.5.Triggers
输出模式定义数据的输出方式,触发器定义数据何时输出——也就是说,结构化流何时应该检查新的输入数据并更新其结果。默认情况下,结构化流将在处理完最后一组输入数据后立即查找新的输入记录,从而为新结果提供尽可能低的延迟。然而,当接收器是一组文件时,这种行为可能导致许多小的输出文件。因此,Spark还支持基于处理时间的触发器(只在固定的时间间隔内查找新数据)。将来,还可能支持其他类型的触发器。
21.2.6.Event-Time Processing事件时间处理
结构化流还支持事件时间处理(即,根据记录中包含的时间戳处理可能出现故障的数据)。这里有两个关键的概念,你们现在需要理解;我们将在下一章更深入地讨论这两个问题,所以如果您现在对它们还不是很清楚,也不要担心。
21.2.6.1.Event-time data事件时间数据
事件时间是指嵌入到数据中的时间字段。这意味着,您不是根据数据到达系统的时间来处理数据,而是根据生成数据的时间来处理数据,即使由于上传速度慢或网络延迟导致流应用程序中的记录无法正常到达流应用程序。
在结构化流中,表示事件时间处理非常简单。因为系统将输入数据视为一个表,所以事件时间只是该表中的另一个字段,您的应用程序可以使用标准SQL操作符进行分组、聚合和窗口操作。然而,在底层,当结构化流知道您的列之一是事件时间字段时,它可以采取一些特殊的操作,包括优化查询执行或确定何时可以安全地忘记关于时间窗口的状态。其中许多操作可以使用水印来控制。
21.2.6.2.Watermarks水印
水印是流处理系统的一个特性,允许您指定希望在事件发生时多晚看到数据。例如,在处理来自移动设备的日志的应用程序中,由于上传延迟,日志可能会延迟30分钟。支持事件时间(包括结构化流)的系统通常允许设置水印,以限制需要记住旧数据的时间。水印还可以用于控制何时为特定的事件时间窗口输出结果(例如,等待水印通过)。
21.3.Structured Streaming 实战