内容:
1. Spark Streaming运行机制
2. Spark Streaming架构
一、Spark Streaming运行机制
上节课回顾:通过第一课,我们了解到SparkStreaming更像Spark core之上的一个应用程序。但是Spark Streaming会启动很多Job,并且多个Job协作一起完成流式数据的处理。
在此基础上,我们来看看SparkStreaming的运行机制和整体架构。
为了更好的了解SparkStreaming的运行,这里让我们先来看看Spark core与Spark Streaming的关系吧。
图2-1 SparkStreaming与Spark Core的关系
这里可以看出,SparkStreaming是Spark core之上的一个子框架,因而Spark Streaming要想利用Spark Core来进行复杂的计算,必须将其引入的DStream转换为RDD才能实现在底层Spark Core上进行计算。(其实其他框架,最终都是将自己的数据最终转化为RDD,进而调用Spark core来进行计算的。)
在为引入上层的子框架时,我们在Spark进行编程大都是是基于RDD的,而在最近几个版本中,引入了一些新的概念(DataFrame、DataSet (Spark SQL编程的基础)、DStream(Spark Streaming))。其实这些概念到底层都会归结到RDD的处理之上。这是由于Spark Core是基于RDD所限定的。
这里,我回顾一下,每一层次的Spark处理的数据逻辑,以便大家更好的了解Spark Streaming。
图2-2 Spark 各部分对应关系
从执行的角度来说,Spark core会根据RDD构建RDD的DAG,相应的Spark Streaming则会根据DStream构建DStream的DAG。
图2-3 DStreamGraph与RDD Graph对应关系
上图是一个BatchInterval中SparkStreaming将DStream Graph(由用户定义的逻辑生成的DAG)转化为RDD的Graph,从而在Spark core进行计算,得到输出结果。而这里的Batch Interval是由时间确定的。所以可以说Spark Streaming是Spark RDD的处理逻辑加上了时间这个维度,不在是单一的一个业务逻辑执行一次即表示程序执行完成;而Spark Streaming则是随着时间不断循环执行业务处理逻辑,对这一时间段内的数据进行处理,这个”应用程序”是在连续不断运行的。
为了更好的解释,SparkStreaming运行机制,这里将其运行划分为两个维度(分别定义为时间维度和空间维度),并将其运行过程表述如图2-4。
图2-4 SparkStreaming运行时空图
通这张图,我们可以了解到Spark运行的内部逻辑和设计思路了。其实随着时间的流逝,DStream Graph会不断的生成以RDD Graph即Job运行的DAG,并触发这些Job;通过JobScheduler的线程池的方式提交给Spark 集群来通过Spark Core不断执行这些Job。
我们有必要在这张图的基础上,深入思考下SparkStreaming有哪些必要的部分或者组件。
1)DStreamGraph
首先,从Spark Streaming架构角度来看,它是利用了将连续数据离散化的思想来实现对流式数据的处理的。这里就必须要有一个对于离散化后的数据的处理逻辑,而这个处理逻辑是静态的,基本上在Spark Streaming运行过程中不会改变的。其实这就是我们所说的RDD Graph的模板DStream Graph。这个类里定义了处理的逻辑,而RDD Graph只不过是DStream Graph具体的实例而已。
DStream Graph类如下
final private[streaming] class DStreamGraph extends Serializable with Logging {
//定义输入流 InputDStream继承自Dstream
private val inputStreams = new ArrayBuffer[InputDStream[_]]()
//定义输出流
private val outputStreams = new ArrayBuffer[DStream[_]]()
var rememberDuration: Duration = null
var checkpointInProgress = false
var zeroTime: Time = null
var startTime: Time = null
//定义时间间隔
var batchDuration: Duration = null
def start(time: Time) {//省略剩下部分代码
2)Job控制器
这里的DStream Graph只是一个Template,SparkStreaming还需要一个基于时间的Job控制器,来不断的实例化DStream Graph为RDD Graph才能进行Job的处理。这个控制器将会在设定的时间内收集的数据填充到RDD Graph中,即作为输入数据来执行Job。
3)InputDStreams和OutputDStream
进一步,我们整体来看,Job运行需要处理InputStreams(输入数据)和处理后产生outputStreams(输出数据)。
4)容错
此外,具体的Job运行在Spark集群上,就不可避免的需要考虑容错的问题。具体来讲,Spark Streaming运行是一系列的Job,而这些Job是基于RDD的,那么单个Job的容错这里就可以利用RDD的高容错性。在此基础上,Spark Streaming自己也有容错的处理(例如限流处理、动态调整系统内存、CPU等的使用等等)。
5)事物
还有一点就是事物处理。这对于某些应用场景是十分重要的,例如网站广告点击计费。这就需要系统在处理出现崩溃的情况下,如何保证Exactly once的事物语义。
请记住这5点,我们后面将会从这5点来思考SparkStreaming。
其实,SparkStreaming是基于DStream进行编程的,DStream其实就是对RDD的一层抽象,其内部也有compute方法和dependencies方法,这与RDD极其相似。最重要的一点是它内的generatedRDDS收集了一个时间间隔的所有RDD。
//Dstream.scala
//RDDs生成器会将RDD放入一个以Time为key的HashMap中
@transient
private[streaming] var generatedRDDs = new HashMap[Time, RDD[T]] ()
从这个层次来看,DStream就是逻辑级别的,而底层RDD则是相应的物理具体执行级别。
最后,我们来看看SparkStreaming整体运行图。
图2-5 Spark Streaming运行图
说明:
本文是由DT大数据梦工厂的定制班课程为基础上,加入一些参考资料所做的笔记