Spark Worker原理和源码剖析解密(DT大数据梦工厂)

内容:

1、Spark Worker原理剖析;

2、Worker启动Driver源码解密;

3、Worker启动Executor源码解密;

4、Worker与Master的交互解密;

==========原理============

1、Master会发送LaunchDriver和LaunchExecutor给Worker

2、LaunchDriver的时候会创建DrvierRunner对象来运行,内部使用Thread来处理Driver的启动

这个时候会创建Driver在本地系统的工作目录

封装好Drvier启动的Command,并通过ProcessBuilder来启动Driver

非Driver部分属于Worker进程,Drvier部分就是Driver进程;

3、LaunchExecutor的时候会创建DriverExecutorRunner对象来运行,内部使用Thread来处理Driver的启动

创建Executor在本地系统的工作目录

封装Executor启动的Command,并使用ProcessBuilder来启动Executor进程

非Executor部分和第2步的统一属于Worker进程,Executor进程就是ExecutorBackend

Executor启动之后向Driver注册给Scheduler;

spacer.gif

==========Worker启动Driver源码解密 ============

1、Cluster中的Driver失败的时候,如果supervise为true的话,则启动该Driver的Worker会负责重新启动该Drvier;

2、DriverRunner启动的时候,里面首先创建目录,然后把jar包下载到这个目录,从下面的代码可以看出 ,jar包是下载到hadoop文件系统中的;

3、DriverRunner启动进程是通过ProcessBuilder中的process.get.waitFor来完成;

/** Starts a thread to run and manage the driver. */
private[worker] def start() = {
  new Thread("DriverRunner for " + driverId) {
    override def run() {
      try {
        val driverDir = createWorkingDirectory()
        val localJarFilename = downloadUserJar(driverDir)

        def substituteVariables(argument: String): String = argument match {
          case "{{WORKER_URL}}" => workerUrl
          case "{{USER_JAR}}" => localJarFilename
          case other => other
        }

        // TODO: If we add ability to submit multiple jars they should also be added here
        val builder = CommandUtils.buildProcessBuilder(driverDesc.commandsecurityManager,
          driverDesc.memsparkHome.getAbsolutePathsubstituteVariables)
        launchDriver(builderdriverDirdriverDesc.supervise)
      }
      catch {
        case e: Exception => finalException Some(e)
      }

      val state =
        if (killed) {
          DriverState.KILLED
       else if (finalException.isDefined) {
          DriverState.ERROR
       else {
          finalExitCode match {
            case Some(0) => DriverState.FINISHED
            case _ => DriverState.FAILED
          }
        }

      finalState Some(state)

      worker.send(DriverStateChanged(driverIdstatefinalException))
    }
  }.start()
}

/**
 * Download the user jar into the supplied directory and return its local path.
 * Will throw an exception if there are errors downloading the jar.
 */
private def downloadUserJar(driverDir: File): String = {
  val jarPath = new Path(driverDesc.jarUrl)

  val hadoopConf = SparkHadoopUtil.get.newConfiguration(conf)
  val destPath = new File(driverDir.getAbsolutePathjarPath.getName)
  val jarFileName = jarPath.getName
  val localJarFile = new File(driverDirjarFileName)
  val localJarFilename = localJarFile.getAbsolutePath

  if (!localJarFile.exists()) { // May already exist if running multiple workers on one node
    logInfo(s"Copying user jar $jarPath to $destPath")
    Utils.fetchFile(
      driverDesc.jarUrl,
      driverDir,
      conf,
      securityManager,
      hadoopConf,
      System.currentTimeMillis(),
      useCache = false)
  }

  if (!localJarFile.exists()) { // Verify copy succeeded
    throw new Exception(s"Did not see expected jar $jarFileName in $driverDir")
  }

  localJarFilename
}

private def launchDriver(builder: ProcessBuilderbaseDir: Filesupervise: Boolean) {
  builder.directory(baseDir)
  def initialize(process: Process): Unit = {
    // Redirect stdout and stderr to files
    val stdout = new File(baseDir"stdout")
    CommandUtils.redirectStream(process.getInputStreamstdout)

    val stderr = new File(baseDir"stderr")
    val formattedCommand = builder.command.asScala.mkString("\"""\" \"""\"")
    val header = "Launch Command: %s\n%s\n\n".format(formattedCommand"=" 40)
    Files.append(headerstderrUTF_8)
    CommandUtils.redirectStream(process.getErrorStreamstderr)
  }
  runCommandWithRetry(ProcessBuilderLike(builder)initializesupervise)
}

private[worker] def handleDriverStateChanged(driverStateChanged: DriverStateChanged): Unit = {
  val driverId = driverStateChanged.driverId
  val exception = driverStateChanged.exception
  val state = driverStateChanged.state
  state match {
    case DriverState.ERROR =>
      logWarning(s"Driver $driverId failed with unrecoverable exception: ${exception.get}")
    case DriverState.FAILED =>
      logWarning(s"Driver $driverId exited with failure")
    case DriverState.FINISHED =>
      logInfo(s"Driver $driverId exited successfully")
    case DriverState.KILLED =>
      logInfo(s"Driver $driverId was killed by user")
    case _ =>
      logDebug(s"Driver $driverId changed state to $state")
  }
  sendToMaster(driverStateChanged)
  val driver = drivers.remove(driverId).get
  finishedDrivers(driverId) = driver
  trimFinishedDriversIfNecessary()
  memoryUsed -= driver.driverDesc.mem
  coresUsed -= driver.driverDesc.cores
}

==========Worker启动Executor源码解密============

case LaunchExecutor(masterUrlappIdexecIdappDesccores_memory_) =>
  if (masterUrl != activeMasterUrl) {
    logWarning("Invalid Master (" + masterUrl + ") attempted to launch executor.")
  } else {
    try {
      logInfo("Asked to launch executor %s/%d for %s".format(appIdexecIdappDesc.name))

      // Create the executor's working directory
      val executorDir = new File(workDirappId + "/" + execId)
      if (!executorDir.mkdirs()) {
        throw new IOException("Failed to create directory " + executorDir)
      }

      // Create local dirs for the executor. These are passed to the executor via the
      // SPARK_EXECUTOR_DIRS environment variable, and deleted by the Worker when the
      // application finishes.
      val appLocalDirs = appDirectories.get(appId).getOrElse {
        Utils.getOrCreateLocalRootDirs(conf).map { dir =>
          val appDir = Utils.createDirectory(dirnamePrefix = "executor")
          Utils.chmod700(appDir)
          appDir.getAbsolutePath()
        }.toSeq
      }
      appDirectories(appId) = appLocalDirs
      val manager = new ExecutorRunner(
        appId,
        execId,
        appDesc.copy(command = Worker.maybeUpdateSSLSettings(appDesc.commandconf)),
        cores_,
        memory_,
        self,
        workerId,
        host,
        webUi.boundPort,
        publicAddress,
        sparkHome,
        executorDir,
        workerUri,
        conf,
        appLocalDirsExecutorState.RUNNING)
      executors(appId + "/" + execId) = manager
      manager.start()
      coresUsed += cores_
      memoryUsed += memory_
      sendToMaster(ExecutorStateChanged(appIdexecIdmanager.stateNoneNone))
    } catch {
      case e: Exception => {
        logError(s"Failed to launch executor $appId/$execId for ${appDesc.name}."e)
        if (executors.contains(appId + "/" + execId)) {
          executors(appId + "/" + execId).kill()
          executors -= appId + "/" + execId
        }
        sendToMaster(ExecutorStateChanged(appIdexecIdExecutorState.FAILED,
          Some(e.toString)None))
      }
    }
  }

private[worker] def handleExecutorStateChanged(executorStateChanged: ExecutorStateChanged):
  Unit = {
  sendToMaster(executorStateChanged)
  val state = executorStateChanged.state
  if (ExecutorState.isFinished(state)) {
    val appId = executorStateChanged.appId
    val fullId = appId + "/" + executorStateChanged.execId
    val message = executorStateChanged.message
    val exitStatus = executorStateChanged.exitStatus
    executors.get(fullId) match {
      case Some(executor) =>
        logInfo("Executor " + fullId + " finished with state " + state +
          message.map(" message " + _).getOrElse("") +
          exitStatus.map(" exitStatus " + _).getOrElse(""))
        executors -= fullId
        finishedExecutors(fullId) = executor
        trimFinishedExecutorsIfNecessary()
        coresUsed -= executor.cores
        memoryUsed -= executor.memory
      case None =>
        logInfo("Unknown Executor " + fullId + " finished with state " + state +
          message.map(" message " + _).getOrElse("") +
          exitStatus.map(" exitStatus " + _).getOrElse(""))
    }
    maybeCleanupApplication(appId)
  }
}

王家林老师名片:

中国Spark第一人

新浪微博:http://weibo.com/ilovepains

微信公众号:DT_Spark

博客:http://blog.sina.com.cn/ilovepains

手机:18610086859

QQ:1740415547

邮箱:[email protected]


本文出自 “一枝花傲寒” 博客,谢绝转载!

你可能感兴趣的:(spark,Worker原理和源码剖析解密)