Spark-Stream 之 Structured Streaming初见
在前面的章节中,我们学习了如何使用结构化API来处理数据规模巨大的有界数据。但是,数据经常连续到达并且需要实时处理。在本章中,我们将讨论如何将相同的结构化API来处理数据流。
1、Apache Spark流处理引擎的演变
流处理被定义为连续处理无穷无尽的数据流。随着大数据时代的到来,流处理系统已从单节点处理引擎过渡到多节点分布式处理引擎。传统的分布式流处理是用一个一次一记录的处理模型来实现的,如下图所示。
处理管道由节点有向图组成,如图8-1所示。每个节点每次连续接收一条记录,进行处理,然后将生成的记录转发到图中的下一个节点。此处理模型可以实现非常低的延迟,也就是说,输入记录可以由管道处理,并且可以在毫秒内生成结果输出。但是,该模型在从节点故障和散乱的节点(即比其他节点慢的节点)中恢复时效率不是很高。它可以使用大量额外的故障转移资源从故障中快速恢复,或者使用最少的额外资源,但是恢复速度相当缓慢。
1.1 微批流处理的出现
当Apache Spark引入Spark Streaming(也称为DStreams)时,这种传统方法受到了挑战。它引入了微批流处理的思想,其中流计算模型是基于一系列连续的微型map/reduce批处理作业实现的(因此称为“微批处理”),如图。
如此处所示,Spark Streaming将来自输入流的数据划分为大小为1秒的微批数据进行处理。每个批次在Spark集群中以分布式方式处理,形成一系列小的确定性任务,这些任务以微批次的形式生成输出。将流计算分解为诸多小任务,与传统的连续运算符模型相比,主要有以下两个优点:
- 通过在其他Executor上重新计划一个或多个任务副本,Spark的敏捷任务调度可以非常快速,有效地从故障和Executor中恢复。
- 任务的确定性确保无论任务重新执行多少次,输出数据都是相同的。这一关键特性使Spark Streaming能够提供端到端的精确一次处理保证,即,生成的输出结果是由每个输入记录都能够被精确地处理一次而得到的。
这种有效的容错能力确实以时间延迟为代价的,微批模型无法达到毫秒级的时间延迟;通常可以达到几秒钟的延迟(在某些情况下,延迟仅为半秒)。但是,我们已经观察到,对于绝大多数流处理用例而言,微批处理的好处胜过二级延迟的缺点。这是因为大多数流传输管道至少具有以下特征之一:
- 管道不需要严格要求时间延迟低于几秒钟。例如,当按小时作业读取流进行输出时,生成具有亚秒级延迟的输出是没有什么意义的。
- 管道的其他部分存在较大的延迟。例如,如果对传感器写入Apache Kafka(用于摄取数据流的系统)的数据进行批处理以实现更高的吞吐量,那么下游处理系统中的任何优化都无法使端到端延迟低于批处理延迟。
此外,DStream API是在Spark的批处理RDD API的基础上构建的。因此,DStream具有与RDD相同的功能语义和容错模型。因此,Spark Streaming证明了一个统一的处理引擎可以为批处理,交互式和流式处理工作负载提供一致的API和语义。流处理中这种基本的范式转变促使Spark Streaming成为使用最广泛的开源流处理引擎之一。
1.2 从Spark Streaming(DStreams)获得的经验教训
尽管Spark Streaming具备了很多的优点,但DStream API并非没有缺陷。以下是一些存在并且需要改进的关键领域:
缺少用于批处理和流处理的单一API
即使DStream和RDD具有一致的API(即相同的操作和相同的语义),开发人员在将批处理作业转换为流式作业时仍必须显式重写其代码以使用不同的类。
逻辑计划与物理计划之间缺乏隔离
Spark Streaming按照开发人员指定的顺序执行DStream操作。由于开发人员可以有效地指定确切的物理计划,因此没有自动优化的空间,并且开发人员必须手动优化其代码才能获得最佳性能。
缺少对事件时间窗口的本地支持
DStream仅根据Spark Streaming接收每个记录的时间(称为处理时间)来定义窗口操作。但是,许多用例需要根据生成记录的时间(称为事件时间)而不是接收或处理记录的时间来计算窗口聚合。缺少事件时间窗口的本机支持,使开发人员很难通过Spark Streaming构建此类管道。
以上这些缺点形成了结构化流(Structured Streaming)的设计理念,我们将在下面讨论。
1.3 结构化流(Structured Streaming)的设计哲学
基于DStreams的这些教训,结构化流从一开始就设计了一种核心理念——对于开发人员而言,编写流处理管道应该与编写批处理管道一样容易。简而言之,结构化流的指导原则是:
单一,统一的编程模型和接口,用于批处理和流处理
这个统一的模型为批处理和流式工作负载提供了一个简单的API接口。你可以像在批处理中一样在流上使用熟悉的SQL或类似批处理的DataFrame查询(就像你在上一章中学到的那样),从而将容错、优化和迟到数据的潜在复杂性留给引擎本身。在接下来的部分中,我们将研究你可能会编写的一些查询。
流处理的更广泛定义
大数据处理应用程序已经变得足够复杂,以至于实时处理和批处理之间的界线已大大模糊。结构化流的目的是将其适用性从传统的流处理扩展到更广泛的应用类别。从定时应用程序(例如,每隔几个小时)到连续(如传统流应用程序)处理数据的任何应用程序都应使用结构化流来处理数据。
接下来,我们将讨论结构化流使用的编程模型。
2. 结构化流的编程模型
“表”是开发人员在构建批处理应用程序时所熟悉的一个众所周知的概念。通过将数据流视为一张无界的、连续追加的表,结构化流将该概念扩展到流应用程序,如图所示。