本文主要讲解Dstream 如何生成RDD以及如何驱动RDD的调用的?
(1)从Dstream.print()开始
将数据打印出来,取前面几条,最后调用的是:
而regester中是直接将结果作为输出ssc.graph.addOutputStream(this)
上一节中我们知道,JobGenertor会掉用generatedJob来定期启动time调用job.
也就是说,是 DStreamGraph
继续调用了每 outputStream
的 generateJob(time)
方法 —— 而我们知道,只有 ForEachDStream 是 outputStream,所以将调用 ForEachDStream
的 generateJob(time)
方法.比如调用print的时候会调用ForeachDstream的generatoeJob,其中会调用parent.getOrCompute(time)àcomputer(time)方法,compute(time) 的具体实现里,就很简单了:
- (1) 获取 parent DStream 在本 batch 里对应的 RDD 实例
- (2) 以这个 parent RDD 和本次 batch 的 time 为参数,调用 foreachFunc(parentRDD, time) 方法
(2)上面是action的流程,对于transformation又是如何的?
MappedDstream的compute方法
override def compute(validTime: Time): Option[RDD[U]] = {
parent.getOrCompute(validTime).map(_.map[U](mapFunc))
}
可以看到,首先在构造函数里传入了两个重要内容:
- parent,是本 MappedDStream 上游依赖的 DStream
- mapFunc,是本次 map() 转换的具体函数
- 在前文 [DStream, DStreamGraph 详解](1.1 DStream, DStreamGraph 详解.md) 中的 quick example 里的 val pairs = words.map(word => (word, 1)) 的 mapFunc 就是 word => (word, 1)
获取了parent dstream的rdd实例,然后以mapFun为参数调用 .map(mapFunc)
方法,将得到的新 RDD
实例返回.
(3)对于inputstream又是如何的?
可以看到生成的是BlockRdd.
这样串起来了,inputstream生成BlockRdd,transfermation对RDD转换,action实现对数据的输出。
总结:
我们在代码里的两次 print() 操作产生了两个 ForEachDStream
节点 x
和 y
,两次
调用 x.generateJob(time)
和 y.generateJob(time)
方法
x
的 parentDStream.getOrCompute(time)
, d.getOrCompute(time)
; d.getOrCompute(time)
会牵扯 c.getOrCompute(time)
,乃至 a.getOrCompute(time)
, b.getOrCompute(time)
y
节点生成 Job 的过程,与 x
节点的过程非常类似,只是在 b.getOrCompute(time)
时,会命中 get(time)
而不需要触发 compute(time)
了,这是因为该 RDD
实例已经在 x
节点的生成过程中被实例化过一次,所以在这里只需要取出来用就可以了。
整个链条就串起来了!