2.2 Spark Streaming设计思想
第1章对Spark Streaming应用的外部表象做了介绍。那么其内部是怎么运作的呢?
Spark Streaming提供了表示连续数据流的、高度抽象的离散流(DStream)。DStream本质上是对RDD的一层封装。DStream中的每个RDD都包含来自一个时间间隔的数据,如图2-3所示。
图2-3 DStream与RDD的关系
DStream是一个没有边界的集合,没有大小的限制。
DStream代表了时空的概念。图2-3就体现了多个时间段。具体到每个时间段,就是空间的操作,也就是对时间间隔的对应批次的数据的处理。
Spark Streaming应用程序中,除了使用数据源产生的数据流来创建DStream,也会在已有的DStream上使用某种操作来创建新的DStream。图2-4显示的是对行DStream做了flatMap操作,生成单词DStream。
图2-4 利用flatMap操作把行DStream转换为单词DStream的示例
下面用实例来讲解数据处理过程。图2-5(a)显示了实例代码的主要部分。
图2-5 案例:Spark Streaming代码与DStream Graph的对应关系
Spark Streaming程序中一般会有若干个对DStream的操作。DStreamGraph就是由这些操作的依赖关系构成的。Spark Streaming程序转换为Spark执行的作业的过程中使用了DStreamGraph。
从程序到DStreamGraph的转换如图2-5所示。图2-5(a)所示的代码和图2-5(b)所示的DStream Graph是相对应的。
本例代码首先用来生成DStream Graph。前面的操作不会马上执行,而是从每个foreach开始都会进行回溯。从后往前回溯这些操作之间的依赖关系,也就形成了DStream Graph。
执行从DStream到RDD的转换也就形成了RDD Graph,如图2-6所示。
图2-6 案例:执行从DStream到RDD的转换就形成了RDD Graph
空间维度确定之后,随着时间的不断推进,会不断实例化RDD Graph,然后触发Job去执行处理。
Spark Core离不开RDD, Spark Streaming自然也离不开。RDD之间的具体依赖构成了空间维度。DStream就是在RDD的基础上增加了时间维度。所以整个Spark Streaming就是时空维度的。
Spark Core处理的每一步都是基于RDD的,RDD之间有依赖关系。图2-6的例子中,RDD的DAG显示有3个action,会触发3个Job, RDD自下向上依赖,RDD产生Job就会具体地执行。从DSteam Graph中可以看到,DStream的逻辑与RDD基本一致,它就是在RDD的基础上加上了时间的依赖。可以把RDD的DAG叫作空间维度,也就是说整个Spark Streaming多了一个时间维度,也就构成了时空维度。
从这个角度来讲,可以将Spark Streaming放在坐标系中。其中的Y轴是对RDD的操作,RDD的依赖关系构成了整个Job的逻辑;而X轴就是时间,随着时间的流逝,固定的批处理时间间隔(Batch Interval)就会生成一个Job实例,进而在集群中运行。
图2-7是批处理周期为1s的Spark Streaming应用程序在时空维度中的运行图示。
图2-7 Spark Streaming应用程序不断产生Job并执行
对于Spark Streaming来说,当不同的数据来源的数据流进来的时候,基于固定的时间间隔,会形成一系列固定不变的数据集或event集合(例如来自flume和kafka)。而这正好与RDD基于固定的数据集不谋而合,事实上,由DStream基于固定的时间间隔形成的RDD Graph正是基于某一个批次的数据集的。
从图2-7中可以看出,在每一个批次上,空间维度的RDD依赖关系都是一样的,不同的是这5个批次流入的数据规模和内容不一样,所以说生成的是不同的RDD依赖关系的实例。RDD的Graph脱胎于DStream的Graph,也就是说DStream就是RDD的模板,不同的时间间隔生成不同的RDD Graph实例。