spark streaming源码分析之job、rdd、blocks之间是如何对应的?

假设你已经了解job是如何被划分及提交的,若不了解请前往spark streaming 流程详解

当前位置是JobGenerator类的generateJobs的方法,我们重点看上面的generateJobs方法中的这一段:

jobScheduler.receiverTracker.allocateBlocksToBatch(time) 
graph.generateJobs(time)

allocateBlocksToBatch这里做了什么呢?

//我们可以看到receiverTracker中这个方法的实现:
def allocateBlocksToBatch(batchTime: Time): Unit = {
    if (receiverInputStreams.nonEmpty) {
      receivedBlockTracker.allocateBlocksToBatch(batchTime)
    }
  }

通过receivedBlockTracker将真正的数据:block,和batch对应起来。其中receivedBlockTracker有两个map用来存放block信息:streamIdToUnallocatedBlockQueues、timeToAllocatedBlocks。详细不讲啦,有兴趣的可以自己扒代码

⚠️接下来看下:graph.generateJobs(time),这里DStreamGraph做了什么事情呢?

def generateJobs(time: Time): Seq[Job] = {
    
    val jobs = this.synchronized {
      outputStreams.flatMap { outputStream =>
        val jobOption = outputStream.generateJob(time)
      }
    }
   
    jobs
  }

可以看到原来是调用了outputstream的generateJob的方法,我们看一个outputstream的实现,如:ForEachDStream

private[streaming]
class ForEachDStream[T: ClassTag] (
   parent: DStream[T],
   foreachFunc: (RDD[T], Time) => Unit,
   displayInnerRDDOps: Boolean
 ) extends DStream[Unit](parent.ssc) {

 ....

 override def generateJob(time: Time): Option[Job] = {
   parent.getOrCompute(time) match {
     case Some(rdd) =>
       val jobFunc = () => createRDDWithLocalProperties(time, displayInnerRDDOps) {
         foreachFunc(rdd, time)//这里很有意思,以装饰器的模式执行了我们代码里写的那一堆对rdd的处理
       }
       Some(new Job(time, jobFunc))
     case None => None
   }
 }
}

在这里我们可以看到,outputstream其实是调用了parent的Compute方法,一层一层递归,最会会调用到inputstream的Compute方法,那么我们一起看下inputstream的Compute方:

override def compute(validTime: Time): Option[RDD[T]] = {
   val blockRDD = {

    
   val blockInfos = receiverTracker.getBlocksOfBatch(validTime).getOrElse(id, Seq.empty)

   createBlockRDD(validTime, blockInfos)
   }
   Some(blockRDD)
 }

可以看到首先是通过receiverTracker获取到了batch的所有block info,然后new了rdd,这就跟前面的receiverTracker.allocateBlocksToBatch(time)对上了

你可能感兴趣的:(spark streaming源码分析之job、rdd、blocks之间是如何对应的?)