第7課:Spark Streaming源碼解讀之JobScheduler內幕實現和深度思考

接着上一節,JobGenerator每隔batchInterval時間會動態的生成JobSet提交給JobScheduler。JobScheduler接收到JobSet後,如何處理呢?

def submitJobSet(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(new JobHandler(job)))
    logInfo("Added jobs for time " + jobSet.time)
  }
}

這裏會爲每個job生成一個新的JobHandler,交給jobExecutor運行。

private val numConcurrentJobs = ssc.conf.getInt("spark.streaming.concurrentJobs", 1)
private val jobExecutor =
  ThreadUtils.newDaemonFixedThreadPool(numConcurrentJobs, "streaming-job-executor") // 線程池

jobExecutor是一個線程池,線程的個數由參數配置。如果需要多個job同時運行,比如在同一個batchInterval中有多個output,則需要配置該參數。

這裏最重要的處理邏輯是 job => jobExecutor.execute(new JobHandler(job)),也就是將每個 job 都在 jobExecutor 線程池中、用 new JobHandler 來處理。

先來看JobHandler針對Job的主要處理邏輯:

......

if (_eventLoop != null) {
  _eventLoop.post(JobStarted(job, clock.getTimeMillis()))
  // Disable checks for existing output directories in jobs launched by the streaming
  // scheduler, since we may need to write output to an existing directory during checkpoint
  // recovery; see SPARK-4835 for more details.
  PairRDDFunctions.disableOutputSpecValidation.withValue(true) {
    job.run()
  }
  _eventLoop = eventLoop
  if (_eventLoop != null) {
    _eventLoop.post(JobCompleted(job, clock.getTimeMillis()))
  }
  
  ......

也就是說,JobHandler除了做一些狀態記錄外,最主要的就是調用job.run()!這裏就與我們在 DStream 生成 RDD 實例詳解 裏分析的對應起來了: 在ForEachDStream.generateJob(time)時,是定義了Job的運行邏輯,即定義了Job.func。而在JobHandler這裏,是真正調用了Job.run()、將觸發Job.func的真正執行!

wKioL1c3H0vTL8CKAAE_V4rBFBw840.png



備註:

1、DT大數據夢工廠微信公衆號DT_Spark 
2、IMF晚8點大數據實戰YY直播頻道號:68917580
3、新浪微博: http://www.weibo.com/ilovepains



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章