spark源码分析之Master源码主备切换机制分析

                                Master源码分析之主备切换机制

1.当选为leader之后的操作

//ElectedLeader 当选leader
    case ElectedLeader => {
      //从持久化引擎中获取数据,driver,worker,app 的信息
      val (storedApps, storedDrivers, storedWorkers) = persistenceEngine.readPersistedData(rpcEnv)
      state = if (storedApps.isEmpty && storedDrivers.isEmpty && storedWorkers.isEmpty) {
        //如果APP、driver、worker是空的,recoverystate设置为alive
        RecoveryState.ALIVE
      } else {
        //有一个不为空则设置为recovering
        RecoveryState.RECOVERING
      }
      logInfo("I have been elected leader! New state: " + state)
      if (state == RecoveryState.RECOVERING) {
        //判断状态如果为recovering 恢复中,将storedApps,storedDrier,storeWorkers重新注册到master内部缓存结构中
        beginRecovery(storedApps, storedDrivers, storedWorkers)
        recoveryCompletionTask = forwardMessageThread.schedule(new Runnable {
          override def run(): Unit = Utils.tryLogNonFatalError {
            //调用自己的CompleteRecovery()方法
            self.send(CompleteRecovery)
          }
        }, WORKER_TIMEOUT_MS, TimeUnit.MILLISECONDS)
      }
    }

2.调用beginRecovery()方法

 //开始恢复
  private def beginRecovery(storedApps: Seq[ApplicationInfo], storedDrivers: Seq[DriverInfo],
      storedWorkers: Seq[WorkerInfo]) {
    for (app <- storedApps) {
      logInfo("Trying to recover app: " + app.id)
      try {
        //重新注册application
        registerApplication(app)
        //将application状态设置为unknown
        app.state = ApplicationState.UNKNOWN
        //向work中的driver发送masterChanged消息
        app.driver.send(MasterChanged(self, masterWebUiUrl))
      } catch {
        case e: Exception => logInfo("App " + app.id + " had exception on reconnect")
      }
    }
    //将storedDrivers重新加入内存缓存中
    for (driver <- storedDrivers) {
      // Here we just read in the list of drivers. Any drivers associated with now-lost workers
      // will be re-launched when we detect that the worker is missing.
      drivers += driver
    }
    //将storedWorkers重新加入内存缓存中
    for (worker <- storedWorkers) {
      logInfo("Trying to recover worker: " + worker.id)
      try {
        //重新注册worker
        registerWorker(worker)
        //将worker状态修改为unknown
        worker.state = WorkerState.UNKNOWN
        //向work发用masterChanged
        worker.endpoint.send(MasterChanged(self, masterWebUiUrl))
      } catch {
        case e: Exception => logInfo("Worker " + worker.id + " had exception on reconnect")
      }
    }
  }

3.调用registerApplication()方法,重新注册APP

  /**
    * 注册application
    * @param app
    */
  private def registerApplication(app: ApplicationInfo): Unit = {
    val appAddress = app.driver.address
    if (addressToApp.contains(appAddress)) {
      logInfo("Attempted to re-register application at same address: " + appAddress)
      return
    }
    //spark测量系统通注册appsource
    applicationMetricsSystem.registerSource(app.appSource)
    //将APP加入内存缓存中
    apps += app
    idToApp(app.id) = app
    endpointToApp(app.driver) = app
    addressToApp(appAddress) = app
    //等待调度的队列,FIFO的算法
    waitingApps += app
  }

4.重新注册worker

private def registerWorker(worker: WorkerInfo): Boolean = {
    // There may be one or more refs to dead workers on this same node (w/ different ID's),
    // remove them.
    //在同一个节点上可能有一个或多个死掉的worker(不同ID),删除它们。

    workers.filter { w =>
      (w.host == worker.host && w.port == worker.port) && (w.state == WorkerState.DEAD)
    }.foreach { w =>
      workers -= w
    }

    val workerAddress = worker.endpoint.address
    if (addressToWorker.contains(workerAddress)) {
      val oldWorker = addressToWorker(workerAddress)
      if (oldWorker.state == WorkerState.UNKNOWN) {
        // A worker registering from UNKNOWN implies that the worker was restarted during recovery.
        // The old worker must thus be dead, so we will remove it and accept the new worker.
          //从UNKNOWN注册的worker意味着worker在恢复期间重新启动。
        //因此,老worker必须死亡,所以我们会把它删除并接受新的worker。
        removeWorker(oldWorker)
      } else {
        logInfo("Attempted to re-register worker at same address: " + workerAddress)
        return false
      }
    }

    //保存workerInfo到wokers(hashmap)中
    workers += worker
    //保存worker的id到idToWorker(hashmap)中
    idToWorker(worker.id) = worker
    //将work端点的地址保存起来
    addressToWorker(workerAddress) = worker
    true
  }

5.删除旧的worker 调用removeworker()方法

private def removeWorker(worker: WorkerInfo) {
    logInfo("Removing worker " + worker.id + " on " + worker.host + ":" + worker.port)
      //将work状态修改为dead
    worker.setState(WorkerState.DEAD)
    //从idToWorker(hashmap)中去掉workid,
    idToWorker -= worker.id
    //从addressToWorker(hashmap)中去掉worker.endpoint.address
    addressToWorker -= worker.endpoint.address
    for (exec <- worker.executors.values) {
      logInfo("Telling app of lost executor: " + exec.id)
      //向driver中发送executor状态改变
      exec.application.driver.send(ExecutorUpdated(
        exec.id, ExecutorState.LOST, Some("worker lost"), None))
      //从application中删除掉这些executor
      exec.application.removeExecutor(exec)
    }
    for (driver <- worker.drivers.values) {
      if (driver.desc.supervise) {
        logInfo(s"Re-launching ${driver.id}")
        //重新启动
        relaunchDriver(driver)
      } else {
        logInfo(s"Not re-launching ${driver.id} because it was not supervised")
        //删除driver
        removeDriver(driver.id, DriverState.ERROR, None)
      }
    }
    //持久化引擎删除worker
    persistenceEngine.removeWorker(worker)
  }

6.调用completeRecovery()方法

recoveryCompletionTask = forwardMessageThread.schedule(new Runnable {
          override def run(): Unit = Utils.tryLogNonFatalError {
            //调用自己的CompleteRecovery()方法
            self.send(CompleteRecovery)
          }
        }, WORKER_TIMEOUT_MS, TimeUnit.MILLISECONDS)

7.以下是completeRecovery()的具体实现

/**
    *completeRecovery  完成恢复 主备恢复机制
    */
  private def completeRecovery() {
    // Ensure "only-once" recovery semantics using a short synchronization period.
    //使用短的同步时间确保“只有一次”恢复语义。

    //清理机制:1.从内存缓存结构中移除。2.从相关的组件的内存中移除。3.从持久化存储中移除
    if (state != RecoveryState.RECOVERING) { return }
    //将状态修改为正在恢复
    state = RecoveryState.COMPLETING_RECOVERY

    // Kill off any workers and apps that didn't respond to us.
    // 过滤出来任何对我们没有回应的worker和Apps,根据workstate和applicationstate判断是否为unknown
    //然后分别执行removerWorker和finishApplication,来删除worker和application
    //删除worker
    workers.filter(_.state == WorkerState.UNKNOWN).foreach(removeWorker)
    //删除application
    apps.filter(_.state == ApplicationState.UNKNOWN).foreach(finishApplication)

    // Reschedule drivers which were not claimed by any workers
    //重新调度 那些没有回应worker的 drivers
    drivers.filter(_.worker.isEmpty).foreach { d =>
      logWarning(s"Driver ${d.id} was not found after master recovery")
      if (d.desc.supervise) {
        logWarning(s"Re-launching ${d.id}")
        //重新启动driver
        relaunchDriver(d)
      } else {
         //删除driver
        removeDriver(d.id, DriverState.ERROR, None)
        logWarning(s"Did not re-launch ${d.id} because it was not supervised")
      }
    }

    //将state转为alive,代表恢复完成
    state = RecoveryState.ALIVE
    //重新调用schedule()恢复完成
    schedule()
    logInfo("Recovery complete - resuming operations!")
  }

8.调用removWorker()方法,具体实现看第5条

9.master的finishApplication()方法调用了自己的removeApplication(app, ApplicationState.FINISHED)方法

//删除application
  def removeApplication(app: ApplicationInfo, state: ApplicationState.Value) {
    if (apps.contains(app)) {
      logInfo("Removing app " + app.id)
      //从application队列(hashset)中删除当前application
      apps -= app

      idToApp -= app.id
      endpointToApp -= app.driver
      addressToApp -= app.driver.address
      if (completedApps.size >= RETAINED_APPLICATIONS) {
        val toRemove = math.max(RETAINED_APPLICATIONS / 10, 1)
        completedApps.take(toRemove).foreach( a => {
          Option(appIdToUI.remove(a.id)).foreach { ui => webUi.detachSparkUI(ui) }
          applicationMetricsSystem.removeSource(a.appSource)
        })
        completedApps.trimStart(toRemove)
      }
      //加入已完成的application队列
      completedApps += app // Remember it in our history
      //从当前等待运行的application队列中删除当前APP
      waitingApps -= app

      // If application events are logged, use them to rebuild the UI
      asyncRebuildSparkUI(app)

      for (exec <- app.executors.values) {
        //停止executor
        killExecutor(exec)
      }
      app.markFinished(state)
      if (state != ApplicationState.FINISHED) {
        //从driver中删除application
        app.driver.send(ApplicationRemoved(state.toString))
      }
      //从持久化引擎中删除application
      persistenceEngine.removeApplication(app)
      //从新调度任务
      schedule()

      // Tell all workers that the application has finished, so they can clean up any app state.
      //告诉说有的worker,APP已经启动完成了,所以他们可以清空APP state
      workers.foreach { w =>
        w.endpoint.send(ApplicationFinished(app.id))
      }
    }
  }

10。removeApplication()中调用了relaunchDriver()方法

 /**
    * 重新启动driver
    * @param driver
    */
  private def relaunchDriver(driver: DriverInfo) {
      //将driver的worker设置为None
    driver.worker = None
    //将driver的状态设置为relaunching(重新调度)
    driver.state = DriverState.RELAUNCHING
    //将当前的driver重新加入waitingDrivers队列
    waitingDrivers += driver
    //重新开始任务调度
    schedule()
  }

11.removeDriver()方法

 //删除driver
  private def removeDriver(
      driverId: String,
      finalState: DriverState,
      exception: Option[Exception]) {
    //用Scala高阶函数find()根据driverId,查找到driver
    drivers.find(d => d.id == driverId) match {
      case Some(driver) =>
        logInfo(s"Removing driver: $driverId")
        //将driver将内存缓存中删除
        drivers -= driver
        if (completedDrivers.size >= RETAINED_DRIVERS) {
          val toRemove = math.max(RETAINED_DRIVERS / 10, 1)
          completedDrivers.trimStart(toRemove)
        }
        //将driver加入到已经完成的completeDrivers
        completedDrivers += driver
        //从持久化引擎中删除driver
        persistenceEngine.removeDriver(driver)
        //设置drier状态设置为完成
        driver.state = finalState
        driver.exception = exception
        //从worker中遍历删除传入的driver
        driver.worker.foreach(w => w.removeDriver(driver))
        //重新调用schedule
        schedule()
      case None =>
        logWarning(s"Asked to remove unknown driver: $driverId")
    }
  }
}

12.到处处master的主备切换基本上已经完成。
大体流程这里写图片描述
13.如有错误之处还请及时指正,共同学习!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值