SparkStream源码分析:JobScheduler的JobStarted、JobCompleted是怎么被调用的

一,从StreamingContext.start()进入


===>在SparkContext有一个JobScheduler成员会被初始化,JobScheduler会被StreamingContext.start()被调用

private[streaming]valscheduler =newJobScheduler(this)

二,跟进入JobSchedulerstart()方法,发现JobStart,JobCompletedJobSchedulerEvent实现类,是如何被EventLoop调用的呢?

1,跟进去processEvent()方法查看一下,需要传进来具体的子类,才能进行调用JobStrart()

//JobSchedulerEvent这个类是下面case对应的父类

  private def processEvent(event: JobSchedulerEvent) {

    try {

      eventmatch{

       caseJobStarted(job,startTime) =>handleJobStart(job,startTime)

        caseJobCompleted(job,completedTime)=> handleJobCompletion(job,completedTime)

       caseErrorReported(m,e)=> handleError(m,e)

      }

    }catch{

     casee:Throwable=>

        reportError("Error in job scheduler",e)

    }

  }

2,进入EventLoop到底是怎么调用的呢?

==》通过上面代码中 跟进去

eventLoop.start()

===》 eventThread.start()线程使用JDK并发包的BlockingQueue来操作  JobSchedulerEvent的子类      

defstart():Unit= {

  if (stopped.get){

    throw new IllegalStateException(name +" has already been stopped")

  }

  // Call onStart before starting the eventthread to make sure it happens before onReceive

  onStart()

  eventThread.start()

}

===》发现eventThread线程会被BlockingQueue.take()进行阻塞,也就是说队列会一直等到JobStarted或JobCompleted进入才会进行调用


===》如果有元素进入队列,就会回调EventLoop中的onReceive()方法,


===》这样才会真正去执行JobScheduler中的processEvent()


3,返回JobScheduler类之后,思考问题就变成了谁负责将JobStart传到EventLoop中的BlockingQueue队列中的呢?

===》分析一下,Dstream每个Batch Interval 生产的job是由JobGenerator来生成的,猜想JobStarted很有可能和这个类有关系

===》所以先将到“谁负责将JobStart传到EventLoop中的BlockingQueue队列中的呢” 先放一放。先分析一下JobGenerator相关内容。看是否能找到这个答案

 

4,在JobScheduler类中会先实例化成员JobGenerator,

private valjobGenerator=newJobGenerator(this)

==》并且在JobSchedulerstart()方法中会调用JobGenerator.start()方法:

jobGenerator.start()

===》在JobGenerator被初始化时,RecurringTimer也被初始化了,并且向JobGenerator中的EventLoop放进一个GenerateJobs

==》先来分析一下RecurringTimer这个类怎么调用主构造方法的匿名函数;

longTime =>eventLoop.post(GenerateJobs(newTime(longTime)))

===》进入RecurringTimer

classRecurringTimer(clock:Clock,period:Long,callback: (Long)=>Unit,name:String)

  extends Logging {

===》这个匿名函数是被RecurringTimer triggerActionForNextInterval方法调用==》它又被loop方法调用

===loop方法又被RecurringTimer成员中的thread调用

private valthread=newThread("RecurringTimer - "+ name) {

  setDaemon(true)

  override def run() { loop }

}

===》这个thread被RecurringTimer中的start方法调用

/**

 * Start at the given start time.

 */

def start(startTime:Long):Long = synchronized {

  nextTime = startTime

  thread.start()

  logInfo("Started timer for "+ name +" at time "+nextTime)

  nextTime

}

===》RecurringTimer.start方法又被JobGenerator中的startFirstTime()调用,而它又被JobGeneratorstart方法调用

===》即然在JobGenerator中的EventLoop被放进一个GeneratorJobs,就会触发onReceive方法

===onReceive方法会调用processEvent()

override protected def onReceive(event:JobGeneratorEvent):Unit= processEvent(event)

===>就会JobGenerator调用generateJobs(time)

private def processEvent(event:JobGeneratorEvent) {

  logDebug("Got event "+ event)

  event match{

    case GenerateJobs(time) => generateJobs(time)

    case ClearMetadata(time) => clearMetadata(time)

    case DoCheckpoint(time,clearCheckpointDataLater)=>

      doCheckpoint(time,clearCheckpointDataLater)

    case ClearCheckpointData(time) => clearCheckpointData(time)

  }

}

===》而在JobGeneratorgenerateJobs方法中看到个接近,谁负责将JobStart传到EventLoop中的BlockingQueue队列中的呢“的答案了

==》就是下面的

jobScheduler.submitJobSet(JobSet(time,jobs,streamIdToInputInfos))

5,再进入JobSchedulersubmitJobSet方法

defsubmitJobSet(jobSet: JobSet){

  if (jobSet.jobs.isEmpty) {

    logInfo("No jobs added for time "+ jobSet.time)

  } else {

    listenerBus.post(StreamingListenerBatchSubmitted(jobSet.toBatchInfo))

    jobSets.put(jobSet.time,jobSet)

    jobSet.jobs.foreach(job =>jobExecutor.execute(newJobHandler(job)))

    logInfo("Added jobs for time "+ jobSet.time)

  }

}

===》发现jobExecutor.execute(new JobHandler(job))

===>JobScheduler中的JobHandler内部类中发现JobStartedJobCompleted是由JobHandler线程放到EventLoop中。(原来如此。。。哈哈。。。)

===JobStartedpostEventLoop中,就会触发OnRecevie方法,从而再调用processEvent方法,从而每个JobStartHandlerJorStart方法开始处理。

private defprocessEvent(event:JobSchedulerEvent) {

  try {

    eventmatch{

     caseJobStarted(job,startTime) =>handleJobStart(job,startTime)

     caseJobCompleted(job,completedTime)=> handleJobCompletion(job,completedTime)

     caseErrorReported(m,e)=> handleError(m,e)

    }

  } catch {

    case e:Throwable=>

      reportError("Error in job scheduler",e)

  }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值