SparkCore — Executor注册

Executor注册

  注册的机制流程如下,CoarseGrainedExecutorBackend进程启动之后,会立即向Driver发送消息注册RegisterExecutor消息,Driver注册成功之后,会返回RegisteredExecutor消息。然后创建管理启动Task的句柄,将Task封装在TaskRunner线程中,并将其放入线程池运行。
executor注册
  直接看源码,如下所示:

override def onStart() {
    logInfo("Connecting to driver: " + driverUrl)
    rpcEnv.asyncSetupEndpointRefByURI(driverUrl).flatMap { ref =>
      // This is a very fast action so we can use "ThreadUtils.sameThread"
      driver = Some(ref)
      // 向Driver注册executor
      ref.ask[RegisterExecutorResponse](
        RegisterExecutor(executorId, self, hostPort, cores, extractLogUrls))
    }(ThreadUtils.sameThread).onComplete {
      // This is a very fast action so we can use "ThreadUtils.sameThread"
      // 省略代码 ....
      }
    }(ThreadUtils.sameThread)
  }

  executor启动之后,首先会向Driver注册,发送RegisterExecutor消息,接着Driver接收到消息之后,将Executor的注册信息保存,然后发送RegisteredExecutor消息给Executor,如下所示:

 override def receive: PartialFunction[Any, Unit] = {
    // Driver注册Executor成功之后,会发送回来RegisteredExecutor消息
    case RegisteredExecutor(hostname) =>
      logInfo("Successfully registered with driver")
      // 创建Executor对象,作为执行句柄,它的大部分功能都是通过executor实现的
      executor = new Executor(executorId, hostname, env, userClassPath, isLocal = false)

    case RegisterExecutorFailed(message) =>
      logError("Slave registration failed: " + message)
      System.exit(1)

      // 启动Task
    case LaunchTask(data) =>
      if (executor == null) {
        logError("Received LaunchTask command but executor was null")
        System.exit(1)
      } else {
        // 将Task反序列化
        val taskDesc = ser.deserialize[TaskDescription](data.value)
        logInfo("Got assigned task " + taskDesc.taskId)
        // 用executor执行句柄调用launchTask,来执行task
        executor.launchTask(this, taskId = taskDesc.taskId, attemptNumber = taskDesc.attemptNumber,
          taskDesc.name, taskDesc.serializedTask)
      }
 	// 省略代码.................
  }

  executor在接收到Driver发送的RegisteredExecutor消息之后,就会创建一个executor句柄。然后Executor在接收到来自Driver内部的TaskScheduler发送的LaunchTask消息,会负责启动Task,首先将task反序列化,接着调用launchTask启动task。下面看一下launchTask方法()。

def launchTask(
      context: ExecutorBackend,
      taskId: Long,
      attemptNumber: Int,
      taskName: String,
      serializedTask: ByteBuffer): Unit = {
    // 将对于每一个task,都会创建一个TaskRunner,TaskRunner继承的是Java的多线程中的Runnable接口
    val tr = new TaskRunner(context, taskId = taskId, attemptNumber = attemptNumber, taskName,
      serializedTask)
    // 将TaskRunner放入内存缓存
    runningTasks.put(taskId, tr)
    // 从线程池中取出一个线程,执行task。
    // 线程池自动实现了排队机制,也就是说,如果线程池内的线程暂时没有空闲的话,
    // 那么后续进来的线程需要排队
    threadPool.execute(tr)
  }

  在launchTask中最重要的就是创建TaskRuuner,它是一个线程,里面封装了task的一些信息,将其加入runningTasks缓存,最后放入线程池中去运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值