Spark源码分析10-Schedualer

Spark很重要的一部分是Task的schedual,以下是具体的流程图。



 SchedulableBuilder分为两种,分别是FairSchedulableBuilder和FIFOSchedulableBuilder。主要是pool的getSortedTaskSetQueue方法中调用不同的taskSetSchedulingAlgorithm去排序schedulableQueue

 override def getSortedTaskSetQueue(): ArrayBuffer[TaskSetManager] = {
    var sortedTaskSetQueue = new ArrayBuffer[TaskSetManager]
    val sortedSchedulableQueue = schedulableQueue.sortWith(taskSetSchedulingAlgorithm.comparator)
    for (schedulable <- sortedSchedulableQueue) {
      sortedTaskSetQueue ++= schedulable.getSortedTaskSetQueue()
    }
    sortedTaskSetQueue
  }

 Schedual另一个重要的类就是SchedulerBackend。它的子类有四类分别为MesosSchedulerBackendCoarseMesosSchedulerBackendSimrSchedulerBackendSparkDeploySchedulerBackendMesosSchedulerBackendCoarseMesosSchedulerBackend用于mesos的部署方式,SimrSchedulerBackend用于hadoop部署方式,SparkDeploySchedulerBackend用于纯spark的部署方式。

 

 

SparkDeploySchedulerBackendCoarseGrainedSchedulerBackend的子类,它的start方法中调用了父类的start方法,并且创建了一个AppClent实例,调用client.start()方法注册到masterMaster会通知workcommand启动CoarseGrainedExecutorBackend

override def start() {
    super.start()

    // The endpoint for executors to talk to us
    val driverUrl = "akka.tcp://spark@%s:%s/user/%s".format(
      conf.get("spark.driver.host"),  conf.get("spark.driver.port"),
      CoarseGrainedSchedulerBackend.ACTOR_NAME)
    val args = Seq(driverUrl, "{{EXECUTOR_ID}}", "{{HOSTNAME}}", "{{CORES}}", "{{WORKER_URL}}")
    val command = Command(
      "org.apache.spark.executor.CoarseGrainedExecutorBackend", args, sc.executorEnvs)
    val sparkHome = sc.getSparkHome().getOrElse(null)
    val appDesc = new ApplicationDescription(appName, maxCores, sc.executorMemory, command, sparkHome,
        "http://" + sc.ui.appUIAddress)

    client = new AppClient(sc.env.actorSystem, masters, appDesc, this, conf)
    client.start()
  }

 以下是clientActor处理的消息

override def receive = {
      case RegisteredApplication(appId_, masterUrl) =>
        appId = appId_
        registered = true
        changeMaster(masterUrl)
        listener.connected(appId)

      case ApplicationRemoved(message) =>
        logError("Master removed our application: %s; stopping client".format(message))
        markDisconnected()
        context.stop(self)

      case ExecutorAdded(id: Int, workerId: String, hostPort: String, cores: Int, memory: Int) =>
        val fullId = appId + "/" + id
        logInfo("Executor added: %s on %s (%s) with %d cores".format(fullId, workerId, hostPort, cores))
        listener.executorAdded(fullId, workerId, hostPort, cores, memory)

      case ExecutorUpdated(id, state, message, exitStatus) =>
        val fullId = appId + "/" + id
        val messageText = message.map(s => " (" + s + ")").getOrElse("")
        logInfo("Executor updated: %s is now %s%s".format(fullId, state, messageText))
        if (ExecutorState.isFinished(state)) {
          listener.executorRemoved(fullId, message.getOrElse(""), exitStatus)
        }

      case MasterChanged(masterUrl, masterWebUiUrl) =>
        logInfo("Master has changed, new master is at " + masterUrl)
        changeMaster(masterUrl)
        alreadyDisconnected = false
        sender ! MasterChangeAcknowledged(appId)

      case DisassociatedEvent(_, address, _) if address == masterAddress =>
        logWarning(s"Connection to $address failed; waiting for master to reconnect...")
        markDisconnected()

      case AssociationErrorEvent(cause, _, address, _) if isPossibleMaster(address) =>
        logWarning(s"Could not connect to $address: $cause")

      case StopAppClient =>
        markDead()
        sender ! true
        context.stop(self)
}

 CoarseGrainedSchedulerBackendstart方法中创建了DriverActor,并调用preStart方法, schedule了一个reviveInterval,每个reviveInterval发送一个ReviveOffersReviveOffers launch task

   override def preStart() {
      // Listen for remote client disconnection events, since they don't go through Akka's watch()
      context.system.eventStream.subscribe(self, classOf[RemotingLifecycleEvent])

      // Periodically revive offers to allow delay scheduling to work
      val reviveInterval = conf.getLong("spark.scheduler.revive.interval", 1000)
      import context.dispatcher
      context.system.scheduler.schedule(0.millis, reviveInterval.millis, self, ReviveOffers)
}

 DriverActor中处理的事件

def receive = {
      case RegisterExecutor(executorId, hostPort, cores) =>
        Utils.checkHostPort(hostPort, "Host port expected " + hostPort)
        if (executorActor.contains(executorId)) {
          sender ! RegisterExecutorFailed("Duplicate executor ID: " + executorId)
        } else {
          logInfo("Registered executor: " + sender + " with ID " + executorId)
          sender ! RegisteredExecutor(sparkProperties)
          executorActor(executorId) = sender
          executorHost(executorId) = Utils.parseHostPort(hostPort)._1
          freeCores(executorId) = cores
          executorAddress(executorId) = sender.path.address
          addressToExecutorId(sender.path.address) = executorId
          totalCoreCount.addAndGet(cores)
          makeOffers()
        }

      case StatusUpdate(executorId, taskId, state, data) =>
        scheduler.statusUpdate(taskId, state, data.value)
        if (TaskState.isFinished(state)) {
          if (executorActor.contains(executorId)) {
            freeCores(executorId) += 1
            makeOffers(executorId)
          } else {
            // Ignoring the update since we don't know about the executor.
            val msg = "Ignored task status update (%d state %s) from unknown executor %s with ID %s"
            logWarning(msg.format(taskId, state, sender, executorId))
          }
        }

      case ReviveOffers =>
        makeOffers()

      case KillTask(taskId, executorId) =>
        executorActor(executorId) ! KillTask(taskId, executorId)

      case StopDriver =>
        sender ! true
        context.stop(self)

      case StopExecutors =>
        logInfo("Asking each executor to shut down")
        for (executor <- executorActor.values) {
          executor ! StopExecutor
        }
        sender ! true

      case RemoveExecutor(executorId, reason) =>
        removeExecutor(executorId, reason)
        sender ! true

      case DisassociatedEvent(_, address, _) =>
        addressToExecutorId.get(address).foreach(removeExecutor(_, "remote Akka client disassociated"))

    }

 MesosSchedulerBackend的部署方式

 在start()方法中启动了MesosSchedulerDriver

override def start() {
    synchronized {
      classLoader = Thread.currentThread.getContextClassLoader

      new Thread("MesosSchedulerBackend driver") {
        setDaemon(true)
        override def run() {
          val scheduler = MesosSchedulerBackend.this
          val fwInfo = FrameworkInfo.newBuilder().setUser("").setName(appName).build()
          driver = new MesosSchedulerDriver(scheduler, fwInfo, master)
          try {
            val ret = driver.run()
            logInfo("driver.run() returned with code " + ret)
          } catch {
            case e: Exception => logError("driver.run() failed", e)
          }
        }
      }.start()

      waitForRegister()
    }
  }

 TaskSchedulerImpl调用submitTasks()时会调用MesosSchedulerBackendreviveOffers()。通知MesosSchedulerDriver reviveOffersMesosSchedulerDriver 会被调用resourceOffers方法,resourceOffers方法中创建了mesosTasks,并且调用launchTasks方法提交taskmesos。bellow is resourceOffers function

 override def resourceOffers(d: SchedulerDriver, offers: JList[Offer]) {
    val oldClassLoader = setClassLoader()
    try {
      synchronized {
        // Build a big list of the offerable workers, and remember their indices so that we can
        // figure out which Offer to reply to for each worker
        val offerableIndices = new ArrayBuffer[Int]
        val offerableWorkers = new ArrayBuffer[WorkerOffer]

        def enoughMemory(o: Offer) = {
          val mem = getResource(o.getResourcesList, "mem")
          val slaveId = o.getSlaveId.getValue
          mem >= sc.executorMemory || slaveIdsWithExecutors.contains(slaveId)
        }

        for ((offer, index) <- offers.zipWithIndex if enoughMemory(offer)) {
          offerableIndices += index
          offerableWorkers += new WorkerOffer(
            offer.getSlaveId.getValue,
            offer.getHostname,
            getResource(offer.getResourcesList, "cpus").toInt)
        }

        // Call into the ClusterScheduler
        val taskLists = scheduler.resourceOffers(offerableWorkers)

        // Build a list of Mesos tasks for each slave
        val mesosTasks = offers.map(o => Collections.emptyList[MesosTaskInfo]())
        for ((taskList, index) <- taskLists.zipWithIndex) {
          if (!taskList.isEmpty) {
            val offerNum = offerableIndices(index)
            val slaveId = offers(offerNum).getSlaveId.getValue
            slaveIdsWithExecutors += slaveId
            mesosTasks(offerNum) = new JArrayList[MesosTaskInfo](taskList.size)
            for (taskDesc <- taskList) {
              taskIdToSlaveId(taskDesc.taskId) = slaveId
              mesosTasks(offerNum).add(createMesosTask(taskDesc, slaveId))
            }
          }
        }

        // Reply to the offers
        val filters = Filters.newBuilder().setRefuseSeconds(1).build() // TODO: lower timeout?
        for (i <- 0 until offers.size) {
          d.launchTasks(offers(i).getId, mesosTasks(i), filters)
        }
      }
    } finally {
      restoreClassLoader(oldClassLoader)
    }
  }

CoarseMesosSchedulerBackend 

CoarseMesosSchedulerBackend也是mesos部署的一种,它和MesosSchedulerBackend区别在于CoarseMesosSchedulerBackend在mesos上运行一个CoarseGrainedExecutorBackend,然后CoarseMesosSchedulerBackend提交task给CoarseGrainedExecutorBackend,让CoarseGrainedExecutorBackend运行。MesosSchedulerBackend是直接将task转化为

 Mesos的task,提交到mesos上运行。下面是createCommand的代码,其他和MesosSchedulerBackend类似。

 def createCommand(offer: Offer, numCores: Int): CommandInfo = {
    val environment = Environment.newBuilder()
    sc.executorEnvs.foreach { case (key, value) =>
      environment.addVariables(Environment.Variable.newBuilder()
        .setName(key)
        .setValue(value)
        .build())
    }
    val command = CommandInfo.newBuilder()
      .setEnvironment(environment)
    val driverUrl = "akka.tcp://spark@%s:%s/user/%s".format(
      conf.get("spark.driver.host"),
      conf.get("spark.driver.port"),
      CoarseGrainedSchedulerBackend.ACTOR_NAME)
      val uri = conf.get("spark.executor.uri", null)
    if (uri == null) {
      val runScript = new File(sparkHome, "./bin/spark-class").getCanonicalPath
      command.setValue(
        "\"%s\" org.apache.spark.executor.CoarseGrainedExecutorBackend %s %s %s %d".format(
          runScript, driverUrl, offer.getSlaveId.getValue, offer.getHostname, numCores))
    } else {
      // Grab everything to the first '.'. We'll use that and '*' to
      // glob the directory "correctly".
      val basename = uri.split('/').last.split('.').head
      command.setValue(
        "cd %s*; ./bin/spark-class org.apache.spark.executor.CoarseGrainedExecutorBackend %s %s %s %d"
          .format(basename, driverUrl, offer.getSlaveId.getValue, offer.getHostname, numCores))
      command.addUris(CommandInfo.URI.newBuilder().setValue(uri))
    }
    command.build()
  }

 SimrSchedulerBackend

目前还没有看懂

 

 

 

 

Kettle入门指南:从安装到数据转换实战 本文提供Kettle(Pentaho Data Integration)的完整入门指南,涵盖从Java环境安装、软件配置到核心概念(转换与作业)的详细解析。通过实战案例,手把手教你如何将文本文件数据导出到Excel,并连接MySQL数据库进行数据导入,帮助你快速掌握这一强大ETL工具的基本使用,实现高效数据搬运与转换。 阅读详情

相关推荐

关于Win11安装Ubuntu子系统报错:WslRegisterDistribution failed with error 解决办法

Win11安装Ubuntu子系统报错:WslRegisterDistribution failed with error

qq_51908382的博客 3万+

Spark任务调度流程及调度策略分析

Spark任务调度 TaskScheduler调度入口: (1) CoarseGrainedSchedulerBackend 在启动时会创建DriverEndPoint. 而DriverEndPoint中存在一定时任务,每隔一定时间(spark.scheduler.revive.interval, 默认为1s)进行一次调度(给自身发送ReviveOffers消息, 进行调用make...

weixin_30819163的博客 254

基于STM32的MAX301032脉率(心率)血氧检测

基于STM32的MAX301032脉率(心率)血氧检测。MAX30102传感器是一个集成的脉搏血氧仪和心率监测器模块。MAX30102传感器运行在一个1.8V电源和一个单独的3.3V电源上,通信是通过一个标准的I2c兼容的接口。当led光射向手腕上皮肤时,人体组织会反射光线给光电变换器,而光电变换器将这个光转换成了电信号并且将它变大和输出,电信号最后再经过A\D转化为数字信号。波长一定的光束在表面的指端皮肤照射后,根据反射或者是投射的反应到接收器上,由于光束受到了手指内的组织、皮肤、血液等的削弱,接收器得到的信号强度也是不会比之前强的,也就是收到了减弱,根据资料了解到手指内的除了血液的其他部分由于变化不大,对光束的削弱吸收是稳定的不变的,由此重点放在了血液上,血液的容积因为心脏的工作呈现波动变化,由此也影响到了光束信号吸收强度也有变化的规律。最后接收器接受到的信号会反应出心脏波动状态,将采集到的信号增益后也可以判断出变化容积脉搏的血流的变化状态。SCL----PA6;SDA----PA7;INT---PA5

spark 作业调度

一、调度分类 调度分为两种,一是应用之间的,二是应用内部作业的。 (一)应用之间 我们前面几章有说过,一个spark-submit提交的是一个应用,不同的应用之间是有调度的,这个就由资源分配者来调度。如果我们使用Yarn,那么就由Yarn来调度。调度方式的配置就在$HADOOP_HOME/etc/hadoop/yarn-site.xml中 [html]view plain...

weixin_34163741的博客 192

Spark常用参数

分类 属性名称 实践 默认值 作用 中文含义

shuijing55hi的博客 1199

一个很奇怪的现象,gird control 里schedualer不能显示

不知道什么原因?Oracle Schedualer 不能显示?!

anddyhua's Cookbook 886

Spark之任务调度

目录 调度模式 调度时机 可调度任务 任务级别 Schedulable 属性 方法 SchedulableBuilder 排序算法 FIFOSchedulingAlgorithm.comparator FairSchedulingAlgorithm.comparator 任务调度器 PreferredLocation Pending Task Task调度器 ...

796

Spark源码走读4——Scheduler

用户提交的Job到DAGScheduler后,会封装成ActiveJob,同时启动JobWaiter监听作业的完成情况。同时依据job中RDD的dependency和dependency属性(NarrowDependency,ShufflerDependecy),DAGScheduler会根据依赖关系的先后产生出不同的stage DAG(result stage, shuffle map ...

weixin_30902251的博客 210

Spark任务提交执行(一)

1、首先上一个画好的阅读Spark任务提交全流程的源码的类调用时序图 spark-submit时序图

qq_32323239的博客 696

spark内核源码深度剖析

深度理解spark内核的前提和作用 1、已经达到可以熟练进行Spark编程的程度。 2、Spark内核源码的研究,是Spark学习的承上启下阶段。 3、内核源码研究透彻之后,才可以通往Spark高手 / Spark精通的道路。 4、才可以继续进行Spark性能优化的学习。 5、才可以在实际工作中,在Spark应用报错出现故障时,读懂log,通过log分析问题的原因,甚至根据log直接到源...

1691

Spark的PIDController源码赏析及backpressure详解

浪尖一直觉得spark 的源码值得我们细细品读,帮助解决我们生产中的问题,可以学习大牛的编程思路,学习spark架构设计,学习scala及java编程,到处都是成长。但是...

大数据星球-浪尖 997

ERROR YarnScheduler: Lost executor 7 on quickstart.cloudera: remote Akka client disassociated

出现原因是存储分配不够,多分配一个就会解决。

xuzhengzheng32的专栏 1667

Timer类的常见使用方法

System.Timers名称空间中的Timer类的构造函数只需要一个时间间隔,经过该时间间隔后应该调用的方法用Elapsed事件指定,这个事件需要一个ElapsedEventHandler类型的委托,这个委托需要objec和ElapsedEventArgs参数。另外它的AutoReset属性是指定计时器是否重复触发,如果这个属性设置为false,事件就触发一次(默认是重复触发的),调用Start...

weixin_30263277的博客 600

Spark-TaskSchedule和TaskScheduleImpl解释和过程

一:什么是TaskSchedule ** 官网的解释 Low-level task scheduler interface, currently implemented exclusively by TaskSchedulerImpl.This interface allows plugging in different task schedulers. Each TaskScheduler sc...

qq_43688472的博客 448

Timer定时器_配置 和 Springle@Scheduled注解

Timer定时器_配置 和 Springle@Scheduled注解

阿狸_桃子 5828

spark 配置整理

spark 的配置有很多,这里一方面总结一下官方文档中的内容,一方面

baiyangfu的专栏 4571

spark源码分析

rdd变换: textfile()加载文件:返回hadoopRDD(创建HadoopRDD之前,先将hadoopConfiguration进行广播)调用map方法,最终返回MapPartitionsRDD 详细流程:https://blog.csdn.net/weixin_43093501/article/details/89492421 rdd提交: sparkcontext运行作...

LaZY的博客 785

Lost executor on YARN

1. Lost executor on YARN ALS iterationsdebasish83 Q:During the 4th ALS iteration, I am noticing that one of the executor gets disconnected: 14/08/19 23:40:00 ERROR network.ConnectionManager: Correspon

power0405hf的专栏 8484

Timer类的schedual()与schedualAtFixedRate()的追赶性区别

使用Timer类对逻辑进行预设时,常用到两个方法,一个是schedual,另一个是schedualAtFixedRate。两者都有多种重载方法,当预设的执行时间在当前时间之后,那么两者执行的效果是完全一样;但是,反之,却出现一个很大的区别,就是追赶性。 schedual方法是不具备追赶性,而schedualAtFixedRate就具备追赶性,到底什么是追赶性呢?下面给两个测试代码...

weixin_30328063的博客 164

Java ScheduledThreadPoolExecutor 一个优于Timer、TimerTask的定时任务

http://bbs.csdn.net/topics/380145101 http://olylakers.iteye.com/blog/1218243 http://zhidao.baidu.com/link?url=ZMRiUrVtBUbXLZIc1kgpTms7QrJAn-122-plrZFmoywmzAGHrYkTkgfLqaZZ-x2WQfA86x6bWIA2rn

7134

APScheduler(Python化的Cron)使用总结

APScheduler(Python化的Cron)使用总结 简介 APScheduler全程为Advanced Python Scheduler,是一款轻量级的Python任务调度框架。它允许你像Cron那样安排定期执行的任务,并且支持Python函数或任意可调用的对象。官方文档:https://apscheduler.readthedocs.io/en/latest/userguide.ht

1万+
上一篇: Spark源码分析9-Excutor
下一篇: Spark源码分析11-BlockManager
fannk
博客等级 码龄20年 2粉丝 94原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值