ExecutorBackend

很简单的接口

package org.apache.spark.executor
/**
* A pluggable interface used by the Executor to send updates to the cluster scheduler.
*/
private[spark] trait ExecutorBackend {
def statusUpdate(taskId: Long, state: TaskState, data: ByteBuffer)
}

 

StandaloneExecutorBackend

维护executor, 并负责注册executor以及executor和driver之间的通信

private[spark] class StandaloneExecutorBackend(
driverUrl: String,
executorId: String,
hostPort: String,
cores: Int)
extends Actor
with ExecutorBackend
with Logging {
var executor: Executor = null
var driver: ActorRef = null override def preStart() {
logInfo("Connecting to driver: " + driverUrl)
driver = context.actorFor(driverUrl) // 创建driver actor ref, 以便于和driver通信
driver ! RegisterExecutor(executorId, hostPort, cores) // 向driver注册executor
} override def receive = {
case RegisteredExecutor(sparkProperties) =>
logInfo("Successfully registered with driver")
// Make this host instead of hostPort ?
executor = new Executor(executorId, Utils.parseHostPort(hostPort)._1, sparkProperties) // 当注册成功后, 创建Executor case RegisterExecutorFailed(message) =>
logError("Slave registration failed: " + message)
System.exit(1) case LaunchTask(taskDesc) =>
logInfo("Got assigned task " + taskDesc.taskId)
if (executor == null) {
logError("Received launchTask but executor was null")
System.exit(1)
} else {
executor.launchTask(this, taskDesc.taskId, taskDesc.serializedTask) // 调用executor.launchTask,启动task
} case Terminated(_) | RemoteClientDisconnected(_, _) | RemoteClientShutdown(_, _) =>
logError("Driver terminated or disconnected! Shutting down.")
System.exit(1)
} override def statusUpdate(taskId: Long, state: TaskState, data: ByteBuffer) {
driver ! StatusUpdate(executorId, taskId, state, data) // 当task状态变化时, 报告给driver actor
}
}

Executor

对于Executor, 维护一个threadPool, 可以run多个task, 取决于core的个数

所以对于launchTask, 就是在threadPool中挑个thread去run TaskRunner

private[spark] class Executor(
executorId: String,
slaveHostname: String,
properties: Seq[(String, String)])
extends Logging
{
  // Initialize Spark environment (using system properties read above)
val env = SparkEnv.createFromSystemProperties(executorId, slaveHostname, 0, false, false)
SparkEnv.set(env)

  // Start worker thread pool
val threadPool = new ThreadPoolExecutor(
1, 128, 600, TimeUnit.SECONDS, new SynchronousQueue[Runnable]) def launchTask(context: ExecutorBackend, taskId: Long, serializedTask: ByteBuffer) {
threadPool.execute(new TaskRunner(context, taskId, serializedTask))
}
}

 

TaskRunner

  class TaskRunner(context: ExecutorBackend, taskId: Long, serializedTask: ByteBuffer)
extends Runnable { override def run() {
try {
SparkEnv.set(env)
Accumulators.clear()
val (taskFiles, taskJars, taskBytes) = Task.deserializeWithDependencies(serializedTask) // 反序列化
updateDependencies(taskFiles, taskJars)
val task = ser.deserialize[Task[Any]](taskBytes, Thread.currentThread.getContextClassLoader) // 反序列化
attemptedTask = Some(task)
logInfo("Its epoch is " + task.epoch)
env.mapOutputTracker.updateEpoch(task.epoch)
taskStart = System.currentTimeMillis()
val value = task.run(taskId.toInt) // 调用task.run执行真正的逻辑
val taskFinish = System.currentTimeMillis()
        val accumUpdates = Accumulators.values
val result = new TaskResult(value, accumUpdates, task.metrics.getOrElse(null)) // 生成TaskResult
val serializedResult = ser.serialize(result) // 将TaskResult序列化
logInfo("Serialized size of result for " + taskId + " is " + serializedResult.limit)
        context.statusUpdate(taskId, TaskState.FINISHED, serializedResult) // 将任务完成和taskresult,通过statusUpdate报告给driver
logInfo("Finished task ID " + taskId)
} catch { // 处理各种fail, 同样也要用statusUpdate event通知driver
case ffe: FetchFailedException => {
val reason = ffe.toTaskEndReason
context.statusUpdate(taskId, TaskState.FAILED, ser.serialize(reason))
} case t: Throwable => {
val serviceTime = (System.currentTimeMillis() - taskStart).toInt
val metrics = attemptedTask.flatMap(t => t.metrics)
for (m <- metrics) {
m.executorRunTime = serviceTime
m.jvmGCTime = getTotalGCTime - startGCTime
}
val reason = ExceptionFailure(t.getClass.getName, t.toString, t.getStackTrace, metrics)
context.statusUpdate(taskId, TaskState.FAILED, ser.serialize(reason)) // TODO: Should we exit the whole executor here? On the one hand, the failed task may
// have left some weird state around depending on when the exception was thrown, but on
// the other hand, maybe we could detect that when future tasks fail and exit then.
logError("Exception in task ID " + taskId, t)
//System.exit(1)
}
}
}
}

Spark源码分析 – Executor的更多相关文章

  1. Spark源码分析 – 汇总索引

    http://jerryshao.me/categories.html#architecture-ref http://blog.csdn.net/pelick/article/details/172 ...

  2. Spark源码分析(三)-TaskScheduler创建

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3879151.html 在SparkContext创建过程中会调用createTaskScheduler函 ...

  3. 【转】Spark源码分析之-deploy模块

    原文地址:http://jerryshao.me/architecture/2013/04/30/Spark%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B9%8B- ...

  4. Spark源码分析:多种部署方式之间的区别与联系(转)

    原文链接:Spark源码分析:多种部署方式之间的区别与联系(1) 从官方的文档我们可以知道,Spark的部署方式有很多种:local.Standalone.Mesos.YARN.....不同部署方式的 ...

  5. Spark 源码分析 -- task实际执行过程

    Spark源码分析 – SparkContext 中的例子, 只分析到sc.runJob 那么最终是怎么执行的? 通过DAGScheduler切分成Stage, 封装成taskset, 提交给Task ...

  6. Spark源码分析 – BlockManager

    参考, Spark源码分析之-Storage模块 对于storage, 为何Spark需要storage模块?为了cache RDD Spark的特点就是可以将RDD cache在memory或dis ...

  7. Spark源码分析 -- TaskScheduler

    Spark在设计上将DAGScheduler和TaskScheduler完全解耦合, 所以在资源管理和task调度上可以有更多的方案 现在支持, LocalSheduler, ClusterSched ...

  8. Spark源码分析 – SchedulerBackend

    SchedulerBackend, 两个任务, 申请资源和task执行和管理 对于SparkDeploySchedulerBackend, 基于actor模式, 主要就是启动和管理两个actor De ...

  9. Spark源码分析 – Deploy

    参考, Spark源码分析之-deploy模块   Client Client在SparkDeploySchedulerBackend被start的时候, 被创建, 代表一个application和s ...

随机推荐

  1. ov5640 i2c通信异常问题

    1 异常场景如下描述 之前的测试场景: 将插在排针上的杜邦线向上拔一点,留出空间挂示波器的探针. 这种方式会导致i2c只发送一组8bit的数据,而另外两组没有发送成功.如上图所示. 因此,之前出现没有 ...

  2. wcf客户端终结点样本集合

    1. <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IUser" /&g ...

  3. C语言 · 求存款

    算法提高 3-2求存款   时间限制:1.0s   内存限制:256.0MB      问题描述 见计算机程序设计基础(乔林)P50第5题. 接受两个数,一个是用户一年期定期存款金额,一个是按照百分比 ...

  4. [shell]Linux脚本开头#!/bin/bash和#!/bin/sh是什么意思以及区别

    一直以为在shell脚本中#都是代表着注释功能,同样在脚本开始的#!/bin/sh也只是告诉用户这是一个shell脚本,而最近顺手查了下,才发现不是这个意思,分享下面的文章. 转自:http://ww ...

  5. js中的target与currentTarget的区别<转>

    关于js中target与currentTarget的区别的关键在于他们所处在的事件流的阶段是不一样的,target处于事件流的目标阶段,currentTarget处理事件流的捕获.处于目标阶段和冒泡阶 ...

  6. web服务器优化的一些思路

    作为一个新手(并不是菜鸟,而是像我们这样的学生),维护一个网站往往是一个很头疼的问题,尤其是动态网站,更尤其是用java写的网站. 当网站的吞吐量很小的时候你会发现服务器根本不需要维护,因为几乎没有延 ...

  7. 程序中判断android系统版本

    public static int getAndroidSDKVersion() { int version; try { version = Integer.valueOf(android.os.B ...

  8. ubuntu 安装dlib 出现dlib.so: undefined symbol: png_set_longjmp_fn

    参考网上的教程安装dlib 安装教程1 sudo apt-get install libboost-python-dev cmake sudo pip install dlib 安装教程2ubuntu ...

  9. 十步理解Sql

    很多程序员视 SQL 为洪水猛兽.SQL 是一种为数不多的声明性语言,它的运行方式完全不同于我们所熟知的命令行语言.面向对象的程序语言.甚至是函数语言(尽管有些人认为 SQL 语言也是一种函数式语言) ...

  10. 错题0920-java

    1.java如何接受request域中的参数? A:request.getRequestURL() B:request. getAttribute() C:request.getParameter() ...