文章目录
DStream虽然在很多方面与弹性分布式数据集(RDD)API相似,但是Dstream API 是基于Java/Python对象的较低级别操作,它限制了更高级别的优化。因此,在2016年,Spark项目增加了结构化流处理(Structured Streaming),这是一个直接建立在DataFrame之上的新式流处理API,支持多种优化策略。
什么是流处理?
流处理是连续处理新到来的数据以更新计算结果的行为。应用程序在运行时将输出多个版本的结果,或者在某外部系统(如键值数据库)中持续保持最新的结果。
批处理是在固定大小输入数据集上进行计算的。批处理也可以进行查询计算,与流处理差不多,但只计算一次结果。
连续应用程序:把包括流处理、批处理和交互式作业等全部作用在同一数据集上的处理环节串联起来,从而构建端到端应用程序,提供最终的处理结果。结构化流处理注重使用简单的端到端的方式构建此类应用程序,而不是仅仅在流数据级别上针对每条记录进行记录。
流处理应用场景
将流处理定义为在无边界数据集上的增量处理。
- 通知和警报
给定一系列事件,如果发生某一事件或一系列连续特殊事件,则应触发通知或警报 - 实时报告
许多组织使用流处理系统来运行员工可以实时查看的动态仪表板 - 增量ETL
减少公司在信息检索时必须忍受的延迟时间,简而言之,“把批处理任务用流处理方式运行”。Spark批处理作业通常用于抽取-转换-加载任务(ETL任务,Extract-Transform-Load),将原始数据转换为结构化格式(如Parquet)以支持高效查询 - 实时数据更新来提供实时服务
流处理系统通常用于为另一个应用程序提供实时的数据处理结果 - 实时决策
流处理系统的实时决策包括分析新的输入,根据业务逻辑自动作出决策来应对新数据 - 在线机器学习
可能希望基于多个用户的流和历史数据的组合来训练模型。这是流处理系统中最具挑战性的应用场景,因为它需要对多个用户的数据进行聚合操作、与静态数据集执行连接操作、与机器想学习库集成等,并同时需要降低延迟响应时间
流处理的优点
在大多数情况下,批处理更容易理解、更容易调试、也更容易编写应用程序。此外,批量处理数据也使得数据处理的吞吐量大大高于许多流处理系统。
但流处理对于以下两种情况非常必要:流处理可以减低延迟时间(状态保存在内存中)和在更新结果方面也比重复的批处理作业更有效。
流处理的挑战
- 基于应用程序时间戳(也称为事件事件)处理无序数据
- 维持大量的状态
- 支持高吞吐量
- 即使有机器故障也仅需对事件进行一次处理
- 处理负载不平衡和拖延者(straggler)
- 快速响应时间
- 与其他存储系统中的数据连接
- 确定在新事件到达时如何更新输出
- 事务性地输出系统写入数据
- 在运行时更新应用程序的业务逻辑
流处理设计要点
为了应对我们所描述的流处理难题,包括高吞吐量、低延迟时间和无序数据处理,有多种方法来设计流处理系统。
记录级别API与声明式API
设计流处理API最简单的方法就是将每个事件传递给应用程序,并使用自定义代码进行响应。这是许多早期的流处理系统(如Apache Storm)的实现方法,当应用程序需要完全控制数据处理时,它具有重要的地位。提供这种记录级别API(record-at-a-time API)的流处理系统只是给用户提供一个获取每条数据记录的接口,然而这些系统的缺点是,我们前面描述的大多数复杂因素(如状态维护)都要完全由应用程序负责。
后来出现的流处理系统提供了声明式API,应用程序为了响应每个新事件指定要计算的内容,而不是如何计算,也不需要考虑如何从失败中恢复。Spark的结构化流处理则更进一步,从功能操作切换到关系操作(类似SQL),从而在不需要编程的情况下实现更丰富的自动执行优化。
基于事件时间与基于处理时间
对于具有声明性API的系统,第二个问题是系统是否支持事件事件。**事件时间(event time)**是根据数据源插入记录中的时间戳来处理数据的概念,而不是流处理应用程序在接受记录时的时间(称为处理时间,processing time)。特别是,当使用事件时间时,记录可能会出现无序状态。如果不基于事件时间,你可能在某些数据延迟到达时无法发现某些重要的模式。
在使用事件时间时,有几个问题需要重点关注,包括以允许系统合并延迟事件的方式跟踪状态,以及确定何时在事件时间内输出给定时间窗口的结果是安全的(即当系统已收到某事件时间点之前的所有输入)
连续处理与微批量处理
在基于连续处理的系统中,系统中的每个节点都不断地侦听来自其他节点的消息并将新的更新输出到其子节点。在输入数据速率较低时,连续处理提供尽可能低的处理延迟,这是连续处理的优势,因为每个节点都会立即响应新消息。但是,连续处理系统通常具有较低的最大吞吐量,因为它们处理每条记录的开销都很大(例如,调用操作系统将数据包发送到下游节点)。此外,连续处理系统通常具有固定的计算拓扑,如果不停止整个系统,在运行状态下是不能够改动的,这也可能会导致负载均衡的问题。
微批量处理系统等待积累少量的输入数据(比如500ms的数据),然后使用分布式任务集合并行处理每个批次,类似于在Spark中执行批处理作业。微批量处理系统通常可以在每个节点上实现高吞吐量,因为它们利用于批处理系统相同的优化操作(例如,向量化操作,Vectorized Processing),并且不会引入频繁处理单个记录的额外开销。缺点是由于等待积累一个微批量而导致更长的响应延迟。
在这两种执行模式之间进行选择时,最主要因素是你期望的延迟和总的操作成本(TCO)
Spark的流处理API
Spark包括两种流处理API,Spark早期的Stream API纯粹是基于微批量处理模式的,它是声明式(基于功能的)API,但不支持事件事件。新的结构化流处理API添加了更高级别的优化、事件时间,并且支持连续处理。
DStream API
拥有高级的API接口和简单的语义,与RDD代码的交互(如与静态数据的连接)也是Spark流处理原生支持的。DStream API有几个限制。首先,它完全基于Java/Python对象和函数,而不是DataFrame和Dataset中丰富的结构化表概念,这不利于执行引擎进行优化。其次,DStream API纯粹基于处理时间(要处理事件时间操作,应用程序需要自己实现它们)。最后,DStream只能以微批量方式运行,并在其API的某些部分暴露了微批量的持续时间,这使得其难以支持其他执行模式。
结构化流处理
结构化流处理是基于Spark结构化API的高级流处理API,它适用于运行结构化处理的所有环境,例如Scala,Java,Python,R和SQL。与DStream一样,它是基于高级操作的声明式API,但是,通过构建本书上一部分介绍的结构化数据模型,结构化流处理可以自动执行更多类型的优化。但是,与DStream不同,结构化流处理对标记事件时间的数据具有原生支持(所有窗口操作都自动支持它)
更重要的是,除了简化流处理之外,结构化流处理还旨在使用Apache Spark轻松构建端到端连续应用程序,这些应用程序结合了流处理、批处理和交互式查询。
总的来看,结构化流处理易于使用且更加高效,它是Spark流处理DStream API的演化。
小结
使用结构化流处理时直接支持DataFrame,因为它避免了重写应用程序逻辑。