spark job生成的时间驱动

JobGenerator中有一个timer成员,根据配置中的时间间隔不断产生GenerateJobs事件来触发job的产生,以成为job产生的起点。Timer通过clock来作为构建时间的依据。

val clock = {
  val clockClass = ssc.sc.conf.get(
    "spark.streaming.clock", "org.apache.spark.util.SystemClock")
  try {
    Utils.classForName(clockClass).newInstance().asInstanceOf[Clock]
  } catch {
    case e: ClassNotFoundException if clockClass.startsWith("org.apache.spark.streaming") =>
      val newClockClass = clockClass.replace("org.apache.spark.streaming", "org.apache.spark")
      Utils.classForName(newClockClass).newInstance().asInstanceOf[Clock]
  }
}

Clock的默认实现是SystemClock,其实现其实就是调用系统api获得当前时间。

def getTimeMillis(): Long = System.currentTimeMillis()

并实现了waitTillTime()方法用来等待直到目标时间到达。

def waitTillTime(targetTime: Long): Long = {
  var currentTime = 0L
  currentTime = System.currentTimeMillis()

  var waitTime = targetTime - currentTime
  if (waitTime <= 0) {
    return currentTime
  }

  val pollTime = math.max(waitTime / 10.0, minPollTime).toLong

  while (true) {
    currentTime = System.currentTimeMillis()
    waitTime = targetTime - currentTime
    if (waitTime <= 0) {
      return currentTime
    }
    val sleepTime = math.min(waitTime, pollTime)
    Thread.sleep(sleepTime)
  }
  -1
}

此处实现的细节,并不是计算完毕当前的时间和系统事件的差距而直接进行sleep相应的时间,而是首先计算距离当前时间的十分之一(但不能小于0.025秒),作为单次的最大休眠时间,该线程会不断sleep最大休眠时间与距离目标时间差距时间的小者,以便在分段休眠中达到尽可能精确的目的。


private val timer = new RecurringTimer(clock, ssc.graph.batchDuration.milliseconds,
  longTime => eventLoop.post(GenerateJobs(new Time(longTime))), "JobGenerator")

而后在JobGenerator将会把clock作为入参构建一个RecuringTimer,并在这里实现了callback函数用来在达到时间的时候向eventloop发送GenerateJobs事件驱动job生成,生成job的时间间隔也就是在StreamingContext中配置的生成批的间隔。

private def triggerActionForNextInterval(): Unit = {
  clock.waitTillTime(nextTime)
  callback(nextTime)
  prevTime = nextTime
  nextTime += period
  logDebug("Callback for " + name + " called at time " + prevTime)
}

private def loop() {
  try {
    while (!stopped) {
      triggerActionForNextInterval()
    }
    triggerActionForNextInterval()
  } catch {
    case e: InterruptedException =>
  }
}

在timer的实现RecuringTimer中,实则实现了一个线程不断调用loop方法,在loop方法中将会调用triggerActionForNextInterval()方法通过上述的clock的waitTillTime()方法在配置好的时间间隔之后触发上文的作为入参传递的callback函数向eventloop发送GenerateJobs事件驱动job生成。

发布了141 篇原创文章 · 获赞 19 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/weixin_40318210/article/details/103813373