Spark Job提交的整体流程源码详解

Spark系列文章一:Spark 提交任务流程详解 一、spark提交任务流程概述 1.1、流程概述 1、构建spark执行环境(初始化sparkcont); 2、SparkContext向资源管理器注册并申请Executor资源; 3、资源管理器分配Executor资源,Executor向资源管理器发送心跳汇报状态; 4、Executor向sc注册并申请task; 5、sc向Executor发送task,Executor执行task; 6、运行完成后,sc向资源管理器申请注销资源。 1.2、流程图解(多图) 二、spark... 阅读详情

Spark Job提交的整体流程源码分析

本文基于spark3.0.1.

任何一个行动算子,都会执行:runJob()

val results = sc.runJob()
runJob()在DAGScheduler类中

1. 提交job,是一个阻塞线程
	val waiter = submitJob(rdd, func, partitions, callSite, resultHandler, properties) //742
2. submitJob中:
   val jobId = nextJobId.getAndIncrement() //生成JobId,  696

3. if (partitions.isEmpty) {
    return new JobWaiter()  //如果分区为空,跳出这个方法  708
   }

4. eventProcessLoop.post(JobSubmitted) //向事件循环中提交事件  714

5.post方法中:
  eventQueue.put(event) //将事件放入队列  105

6. 在eventQueue中会起一个线程,会不断从队列中取出事件。
private[spark] val eventThread = new Thread(name) {
    override def run(): Unit = {
        while (!stopped.get) 
          val event = eventQueue.take()
            onReceive(event)  //79  在EventLoop类中
    }
}

7.onReceive是一个抽象方法,其实现方法中执行doOnReceive(event):
	override def onReceive(event: DAGSchedulerEvent): Unit = {
	      doOnReceive(event)  //2152
    }

8. doOnReceive(event)中:
	private def doOnReceive(event: DAGSchedulerEvent): Unit = event match {
     //上面向eventProcessLoop中post就是JobSubmitted
    case JobSubmitted(jobId, rdd, func, partitions, callSite, listener, properties) =>
      dagScheduler.handleJobSubmitted(jobId, rdd, func, partitions, callSite, listener, properties)
    }

"-----------DAGScheduler开始工作--------------"

9. dagScheduler.handleJobSubmitted :正式处理我们提交的Job
   handleJobSubmitted中:
   var finalStage: ResultStage = null // 从后面往前推 982
   finalStage = createResultStage(finalRDD, func, partitions, jobId, callSite) //986

10. createResultStage方法中:
    //先获得ParentStages,即ShuffleMapStage
    val parents = getOrCreateParentStages(rdd, jobId) //454
    //根据ShuffleMapStage创建ResultStage
    val stage = new ResultStage(id, rdd, func, partitions, parents, jobId, callSite)
      
11. private def getOrCreateParentStages(rdd: RDD[_], firstJobId: Int): List[Stage] = {
    //获取最后一个RDD的shuffle依赖,只获取直接父级的shuffle依赖,再往前的不获取
    getShuffleDependencies(rdd).map { shuffleDep =>
      getOrCreateShuffleMapStage(shuffleDep, firstJobId)
    }.toList
  }

12. getShuffleDependencies()中:

	private[scheduler] def getShuffleDependencies(
      rdd: RDD[_]): HashSet[ShuffleDependency[_, _, _]] = {
      //存储的是当前RDD有shuffle依赖的的直接父RDD的shuffle依赖信息
    val parents = new HashSet[ShuffleDependency[_, _, _]]
    // 存储哪些已经查找过了的RDD
    val visited = new HashSet[RDD[_]]
    //存储哪些是待查找的RDD
    val waitingForVisit = new ListBuffer[RDD[_]]
    // 将待查找的RDD加入集合
    waitingForVisit += rdd
    //如果集合非空,刚放进去,肯定不是空
    while (waitingForVisit.nonEmpty) {
        //获取要查找的RDD
      val toVisit = waitingForVisit.remove(0)
        // 如果还没有查找过
      if (!visited(toVisit)) {
          //就先添加到已经访问过的RDD的Set中,下一步再对它获取依赖关系
        visited += toVisit
          // 获取依赖关系
        toVisit.dependencies.foreach {
            //如果是shuffle依赖(宽依赖)
          case shuffleDep: ShuffleDependency[_, _, _] =>
            //加入shuffle依赖的集合
            parents += shuffleDep
            //如果是窄依赖
          case dependency =>
            //将其父RDD添加到待查找的集合前面,按此一直往前找,直到找到shuffle依赖
            waitingForVisit.prepend(dependency.rdd)
        }
      }
    }
    //返回当前节点的shuffle依赖
    parents
  }

13. 回到第 11 步:
	getShuffleDependencies(rdd).map { shuffleDep =>
      //一旦查找到父RDD的shuffle依赖信息,此时就创建一个ShuffleMapStage
      getOrCreateShuffleMapStage(shuffleDep, firstJobId)
    }.toList

"---------------DAGScheduler开始根据shuffle划分stage--------------"

14. getOrCreateShuffleMapStage()中:
	shuffleIdToMapStage.get(shuffleDep.shuffleId) match {
      case Some(stage) =>
        stage
      case None =>
        // 为当前shuffle依赖的所有祖先shuffle依赖创建ShuffleMapStage,注意,是所有
        getMissingAncestorShuffleDependencies(shuffleDep.rdd).foreach { dep =>
          if (!shuffleIdToMapStage.contains(dep.shuffleId)) {
            createShuffleMapStage(dep, firstJobId)
              
             createShuffleMapStage方法中:
              //继续调用getOrCreateParentStages,其实就是利用递归一层一层往上找
			val parents = getOrCreateParentStages(rdd, jobId) //391
			val stage = new ShuffleMapStage()
          }
        }
        // 最后,再创建当前shuffle依赖关系的ShuffleMapStage
        createShuffleMapStage(shuffleDep, firstJobId)  //358  
        
        //至此,所有的ShuffleMapStage创建完成,还有resultStage没创建
    }


15. 然后,看第 10 步,根据ShuffleMapStage创建ResultStage, 然后赋值给第 9 步的finalStage
	val stage = new ResultStage(id, rdd, func, partitions, parents, jobId, callSite) //456

16. 获得finalStage后,接第 9 步,往下
	//如果是ResultStage,提交result-job,如果是ShuffleMapStage,运行 map-shuffle job
	val job = new ActiveJob(jobId, finalStage, callSite, listener, properties) //1022

17. finalStage.setActiveJob(job) //1033

18. submitStage(finalStage) //1038 提交最后的阶段,DAGScheduler完成工作

19. submitStage方法中:
	/* Submits stage, but first recursively submits any missing parents. */
	/* 翻译:首先会递归提交所有缺失的ShuffleMapStage*/
  private def submitStage(stage: Stage): Unit = 
      //判断是否有正在等待提交的,正在运行的,提交失败的ShuffleMapStage
      if (!waitingStages(stage) && !runningStages(stage) && !failedStages(stage)) 
          //如果有将这些ShuffleMapStage按照ID升序排序,ID小的会被优先提交
        val missing = getMissingParentStages(stage).sortBy(_.id)
          //如果没有这些ShuffleMapStage
        if (missing.isEmpty) 
          //提交当前就是封装Task来运行这个阶段的逻辑
          submitMissingTasks(stage, jobId.get)
            
  		 submitMissingTasks方法中:
            
   				val tasks: Seq[Task[_]] = try   //1217
    			  stage match {
    			    case stage: ShuffleMapStage =>
    			      partitionsToCompute.map { id =>
    			        //如果是ShuffleMapStage,每个分区都创建一个 ShuffleMapTask
    			        new ShuffleMapTask())
    			      }
    			    case stage: ResultStage =>
    			      partitionsToCompute.map { id =>
    			        //如果是ShuffleMapStage,每个分区都创建一个 ResultTask
    			        new ResultTask()
    			      }
                  }

                    if (tasks.nonEmpty) { //1249
                        //taskScheduler将Task以TaskSet的形式提交
      				  taskScheduler.submitTasks(new TaskSet, ...) ---此处转到taskScheduler干活
                                                )
                    }
        } else {
          //如果有这些ShuffleMapStage,就一个个的递归提交
          for (parent <- missing) {
            submitStage(parent)
          }
        }

"---------------taskScheduler开始干活---------------"

1. taskScheduler.submitTasks(new TaskSet, ...)):
   submitTasks是一个抽象方法,其实现方法:
       val tasks = taskSet.tasks //将task从taskset中取出来
	  //创建一个TaskSetManager,每个taskset都会创建一个taskmanager
	   val manager = createTaskSetManager(taskSet, maxTaskFailures)  //219
      //将创建的 TaskSetManager加入到 schedulableBuilder(任务调度池)中   
	 schedulableBuilder.addTaskSetManager(manager, manager.taskSet.properties)
    
 'SchedulableBuilder介绍:是一个特质,其有两个实现类:FIFOSchedulableBuilder和FairSchedulableBuilder,有三个方法,分别是根调度池和子调度池,和addTaskSetManager。根调度池下有Schedulablequeue,其中便放置TaskSetManager。SparkContext初始化时,默认使用FIFOSchedulableBuilder。

	 //从调度池中,取出TaskSetManager,开始调度
    backend.reviveOffers() // backend是一个SchedulerBackend对象,负责系统的调度通讯
        
2. reviveOffers() 中:
   reviveOffers() 是一个SchedulerBackend的抽象方法,其实现方法在CoarseGrainedSchedulerBackend中:
     override def reviveOffers(): Unit = {
    driverEndpoint.send(ReviveOffers)  //向driverEndpoint发送ReviveOffers消息
  }
  
3. send方法需要在receive方法中查看,DriverEndpoint的receive方法中:
   override def receive: PartialFunction[Any, Unit] = {
       case ReviveOffers =>
        makeOffers()  //169
       ...
   }
4. makeOffers()中:
   //筛选当前active状态的所有的executors
   val activeExecutors = executorDataMap.filterKeys(isExecutorActive) //291
   val workOffers = activeExecutors.map{
	case (id, executorData) => new WorkerOffer   // 每个active的executor都创建一个 WorkerOffer
	}

  //此方法由集群调用,在集群的slave准备资源。根据TaskSet的优先级,以轮询的方式发送到任务,以保证负载均衡
   val taskDescs = scheduler.resourceOffers(workOffers) //300

5. resourceOffers()中:
   //获得一个排序后的TaskSet集合
   val sortedTaskSets = rootPool.getSortedTaskSetQueue.filterNot(_.isZombie) // 436

6. getSortedTaskSetQueue()中:
     val sortedTaskSetQueue = new ArrayBuffer[TaskSetManager]
     //从rootPool中获取schedulableQueue,之后将队列中的TaskSet,调用调度算法(FIFO)进行排序
     val sortedSchedulableQueue =
      schedulableQueue.asScala.toSeq.sortWith(taskSetSchedulingAlgorithm.comparator)
    taskSetSchedulingAlgorithm默认是FIFOSchedulingAlgorithm(),是通过stageId进行比较的
   这个方法得到一个按stageId从小到大排序后的TaskSet集合

7. 得到排序后的taskset集合后,再获取集合中每一个taskset'最高的本地化级别
	for (taskSet <- sortedTaskSets) {
        for (currentMaxLocality <- taskSet.myLocalityLevels)  //462
        ...
    }

    '关于本地化级别:myLocalityLevels是TaskSetManager的一个属性,本地化级别有五种:
	PROCESS_LOCAL, NODE_LOCAL, NO_PREF, RACK_LOCAL, ANY
    Spark调度总是会尽量让每个task以最高的本地性级别来启动,即PROCESS_LOCAL(进程本地化),是让task和数据都     同在一个executor中,这种情况性能最佳。

8. return tasks //返回各种处理后的tasks,第 4 步的resourceOffers()就走完了。 557

"------------------下面是将task发往executor------------------"

9. 接第 4 步:
      if (taskDescs.nonEmpty) {
        launchTasks(taskDescs)
      }

    launchTasks():
    //将task的描述信息序列化
    val serializedTask = TaskDescription.encode(task)  //341
    //获取当前Tasks应该发往的executor的信息
    val executorData = executorDataMap(task.executorId)
    //向executorEndpoint发送LaunchTask信息,同时将 TaskDesc也发送过去
    executorData.executorEndpoint.send(LaunchTask(new SerializableBuffer(serializedTask)))
    
    需要在CoarseGrainedExecutorBackend(这个就是executorEndpoint)的receive方法中查看消息:
    override def receive: PartialFunction[Any, Unit] =
        case LaunchTask(data) =>
          val taskDesc = TaskDescription.decode(data.value)  //将task描述信息反序列化
          executor.launchTask(this, taskDesc) //166

    launchTask()中:
    val tr = new TaskRunner(context, taskDescription) //创建一个运行task的线程
    TaskRunner线程的run方法中:
    //从之前的task描述信息的中获取真正的task
    task = ser.deserialize[Task[Any]](
          taskDescription.serializedTask, Thread.currentThread.getContextClassLoader) // 406
    //获取task后,run!
    val res = task.run():
    runTask(context) //127
    不同类型的Task运行自己的处理逻辑, 有两种,ShuffleMapTask和ResultTask 

'ShuffleMapTask:
  这个task逻辑是将当前stage的结果写出,然后供下一个stage使用,所以一定会有write方法
  ShuffleMapTask的runTask():
  dep.shuffleWriterProcessor.write(rdd, dep, mapId, context, partition)  //99
  write方法中:
    var writer: ShuffleWriter[Any, Any] = null
	val manager = SparkEnv.get.shuffleManager
	// shuffle以什么形式写出,由shuffleManager决定,可由自己配置
    writer = manager.getWriter
    
    //执行写出操作
    writer.write( 
        rdd.iterator(partition, context).asInstanceOf[Iterator[_ <: Product2[Any, Any]]]) //59

   iterator方法中:
     //判断是否使用了缓存
    if (storageLevel != StorageLevel.NONE) {
        //如果有缓存,直接从缓存中获取EDD
      getOrCompute(split, context)
    } else {
        //如果没有缓存,尝试从checkpoint目录中获取RDD,如果没有就计算得到
      computeOrReadCheckpoint(split, context)
    }
 
'ResultTask:
  runTask():
  //这个func是用户调用行动算子时的逻辑函数
  func(context, rdd.iterator(partition, context)) // 90

"至此,job的提交流程便结束了"

Spark 任务提交流程说明 本篇主要阐述 Spark 任务提交的流程,其主要目的在于通过了解 Spark 任务提交可以清楚大概的流程,并知道每一步是做什么;当遇到问题可以快速的知道是什么环节或者哪一步骤出现了问题,及时定位到问题并解决。目前Spark官方支持五中集群管理模式,分别是 Standalone、Yarn、Mesoes、Kubernetes、Amazon EC2 等。本篇文章主要阐述笔者平时经常使用的 Standalone 与 Yarn 集群管理模式。.................. 阅读详情

相关推荐

一文带你解析Spark的源码:从Spark-Submit任务提交到资源分配Executor

随着互联网的告诉发展,每天会有大量的数据产生,传统的数据分析手段已经不能满足现在的需求。Apache Spark是专为大规模数据处理而设计的快速通用的计算引擎,现在形成一个高速发展应用广泛的生态系统。Spark由于其基于内存的计算模式,能够很好的应用于各个应用场景,包括离线数据分析、在线 数据分析和机器学习等。要想深入的了解Spark,学习其源码实现是必不可少的过程。 在本场 Chat 中,会讲到...

GitChat 4737

Spark job提交过程

本文基于spark2.111. 前言1.1 基本概念RDD关于RDD已经有很多文章了,可以参考一下理解Spark的核心RDD依赖依赖分为窄依赖和宽依赖,下图描述了两种依赖(图片出自spark窄依赖和宽依赖)20160913233559680.jpeg从途中可以看出,窄依赖中,每一个上游RDD中的分区只会被一个下游分区依赖。而宽依赖上游RDD中的分区则可能被多个下游分区依赖。宽依赖往往意味者shuf...

cjlion的专栏 2580

spark最新版本3.0.0中job划分、调度以及任务的提交执行流程源码分析

文章目录前言一 整个任务的流程图示二 任务的划分、调度和执行1 调用行动算子生成job2 划分阶段并发送Task给Executor3 Executor执行Task 前言 上文我们对spark整个应用运行流程进行了整体的分析,但是后面最后一步关于任务的划分、调度和执行就一笔带过了,今天我们就来对spark任务的执行流程的底层源码分析,搞懂这个会对我们理解spark几个术语有比较清楚的理解了,如: 术语 描述 关系 job 工作 调用一个行动算子就会有一个job生成 stage 阶段 有一

newhandnew413的博客 1288

Spark作业提交

角色作用Master管理集群和节点,不参与计算。Driver一个Spark作业运行时包括一个Driver进程,也是作业的主进程,具有main函数,并且有SparkContext的实例,是程序的入口点。负责向集群申请资源,向master注册信息,负责了作业的调度,负责作业的解析、生成Stage并调度Task到Executor上。包括DAGScheduler,TaskScheduler。Woker主要功能:管理当前节点内存,CPU的使用状况,

jpfx6008的博客 1435

计算机组成原理 微程序控制器实验

微程序控制器实验 实验环境 计算机组成原理实验环境 实验目的 掌握微程序控制器的组成原理和工作过程。 理解微指令和微程序的概念,理解微指令与指令的区别与联系。 掌握指令操作码与控制存储器中微程序的对应方法。熟悉根据指令操作码从控制存储器中读出微程序的过程。 实验要求 做好实验预习,读懂实验电路图,熟悉实验元器件的功能特性和使用方法。 按照实验内容与步骤的要求,独立思考,认真仔细地完成实验。 写出实验报告。 实验电路        

Long_UP的博客 7万+

西门子WinCC VBS脚本实战:5分钟搞定变量记录导出到Excel(附完整代码)

本文提供了一套高效的西门子WinCC VBS脚本方案,帮助工程师在5分钟内将变量记录数据导出至Excel。方案详细解析了时区转换、数据库连接、SQL查询优化等核心难点,并附带了完整、可直接使用的VBS代码,解决了工业自动化项目中数据导出的实际痛点。

moss5的博客 609

spark job提交过程

Driver的任务提交过程 1、Driver程序的代码运行到action操作,触发了SparkContext的runJob方法。 2、SparkContext调用DAGScheduler的runJob函数。 3、DAGScheduler把Job划分stage,然后把stage转化为相应的Tasks,把Tasks交给TaskScheduler。 4、通过TaskScheduler把Tasks添加到任务队列当中,交给SchedulerBackend进行资源分配和任务调度。 5、调度器给Task分配执行Exe

Alex_Sheng_Sea的博客 397

【项目实战】小智AI MCP协议在IoT设备控制中的深度应用解析

本文深度解析小智AI MCP协议在IoT设备控制中的应用实践。通过MCP协议作为AI与物联网设备的翻译桥梁,实现大语言模型与ESP32等硬件的无缝通信。文章详细介绍了环境搭建、工具注册、消息路由机制,并以语音控制RGB灯光系统为例展示完整开发流程,为AIoT开发者提供实用指南。

oauth7security的博客 824

6.Spark streaming技术内幕 : Job动态生成原理与源码解析

原创文章,转载请注明:转载自 周岳飞博客(http://blog.youkuaiyun.com/zhouzx2010)   Spark streaming 程序的运行过程是将DStream的操作转化成RDD的操作,Spark Streaming 和 Spark Core 的关系如下图(图片来自spark官网) Spark Streaming 会按照程序设定的时间间隔不断动态生成Jo

听风居士 1635

5分钟搞定DataDome滑块验证码:最新Capsolver API实战教程(含代理配置)

本文提供了一份利用Capsolver API快速自动化破解DataDome滑块验证码的实战教程。文章深入剖析了DataDome验证码的环境指纹与行为分析机制,并重点详解了确保成功率的住宅代理配置、API集成步骤及令牌使用等核心环节,帮助开发者高效集成稳定可靠的自动化解决方案。

milk8的博客 494

【GameFramework框架内置模块】8、文件系统(File System)

最近好忙,鸽了好久。不能颓废了,继续发力。今天分享的是GF框架的文件系统。首先,引用比较官方的说法:GF的FileSystem虚拟文件系统,使用类似磁盘存储的感念对零散的文件进行集中管理,优化资源加载时产生的内存分配,也可以对资源进行局部片段加载,极大的提升了资源加载的性能。通俗点讲就是,我这个模块就是加载磁盘文件的,优化加载时产生的内存分配。那么,它是怎么优化的呢?

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2452

Spark streaming技术内幕6 : Job动态生成原理与源码解析

原创文章,转载请注明:转载自 听风居士博客(http://blog.youkuaiyun.com/zhouzx2010) Spark streaming 程序的运行过程是将DStream的操作转化成RDD的操作,Spark Streaming 和 Spark Core 的关系如下图(图片来自spark官网) Spark Streaming 会按照程序设定的时间间隔不断动态生成Job来处理

听风居士 766

使用蒙特卡洛模拟方法在MATLAB中估算居里温度: 一个详细而通俗的指南

居里温度是磁性材料失去磁性的温度。但是,计算机模拟为我们提供了一个在理论和实验之间的桥梁,使我们能够在不进行实际测量的情况下估计这一重要参数。在下一部分,我们将详细介绍蒙特卡洛迭代的核心代码,以及如何使用它来模拟磁性材料中原子的行为。在估算居里温度的上下文中,我们将使用蒙特卡洛方法来模拟磁性材料中的原子或分子的行为。通过使用蒙特卡洛方法,我们可以在MATLAB中估算居里温度,从而为理论研究和实验设计提供有价值的信息。:我们使用的是一个有限的尺寸的网格模型,这可能导致一些大小效应,特别是在接近居里温度时。

qq_38334677的博客 977

spark源码(五)DAGScheduler TaskScheduler如何配合提交任务,application、job、stage、taskset、task对应关系是什么?

DAGScheduler TaskScheduler如何配合提交任务,各个阶段如何划分? 一个application可能有多个job提交,因为每个行为算子都调用runjob方法,即都对应一次job任务提交 一个job可能有多个stage,划分依据主要是RDD是不是出现了shuffle,即每个宽依赖都会导致新stage的生成。 一个stage对应一个taskset,且为stage中每个分区创建一个task任务。 askset包含一组task,每个task执行逻辑相同,主要是面向stage不同的分区...

Interest1_wyt的博客 775

[QMT量化交易小白入门]-105、震荡市最适合的策略:ETF多标的动态网格策略,回测年化收益47.81%

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写200篇左右。QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

木头大左的博客 2062

解决:请求的资源[/xxx/]不可用 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。

解决:请求的资源[/xxx/]不可用 描述 源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。

念兮为美 1万+

Spark streaming源码分析之Job动态生成原理与源码解析

原创文章,转载请注明:转载自 周岳飞博客(http://blog.youkuaiyun.com/zhouzx2010)  Spark streaming 程序的运行过程是将DStream的操作转化成RDD的操作,Spark Streaming 和 Spark Core 的关系如下图(图片来自spark官网) Spark Streaming 会按照程序设定的时间间隔不断动态生成Job来处理输

听风居士 664

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Spark源码分析之调度框架详解

文章目录原理概述源码分析Job提交Stage划分Task提交Executor端运行Task Spark的调度框架分为资源调度和任务调度。Spark的资源调度是基于Yarn实现的,包含Driver和Executor资源的申请等,详细过程见博文 Spark源码分析之AM端运行流程(Driver) 和 Spark源码分析之CoarseGrainedExecutorBackend运行流程(Executor);本文主要讲述Spark任务调度框架的原理和源码分析。 原理概述 由于 Spark Scheduler内部原理

Haiwi-Song 1292

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

spark2.4.3(一)提交作业的整体流程

任务提交和执行流程 以standalone模式为例的基本流程: spark-submit shell提交Application,提交到Driver进程。Spark使用DriverWrapper启动用户APP的main函数。 Driver进程执行Application应用代码,先构建sparkContext。 sparkContext初始化时,主要是构建出TaskScheduler和DAGScheduler。 TaskScheduler通过后台进程连接Master,向Master注册Application.

rover 662

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

大数据技术之_19_Spark学习_06_Spark 源码解析 + Spark 通信架构、脚本解析、standalone 模式启动、提交流程 + Spark Shuffle 过程 + Spark 内存

https://www.cnblogs.com/chenmingjun/p/10803261.html 文章目录 第1章 Spark 整体概述 1.1 整体概念 1.2 RDD 抽象 1.3 计算抽象 1.4 集群模式 1.5 RPC 网络通信抽象 1.6 启动 Standalone 集群 1.7 核心组件 1.8 核心组件交互流程 1.9 Block 管理...

zdy0_2004的专栏 2448

Spark提交作业运行过程

背景 最近在学习Spark源码方面的知识,在这里大概了解了Spark整体的运行过程,从初始化到最终的底层运行。今天在这里进行详细的记录一下。一边以后的回顾和学习。Spark程序运行整体流程当SparkContext初始化完之后,我们通常会使用它来读取外部的数据,使之形成RDD。然后我们会经过一些列的RDD操作之后,到最后一个Action操作。从而触发了Job的提交。在Spark中RDD操作分为两种:

leishenop的专栏 1196

spark源码(五)--job触发流程以及stage划分算法

master在完成资源分配后,运行一个application的条件就成熟了,下面需要解析的就是如何运行一个app。我们之前提到过,在初始化sparkContext中会初始化一个taskScheduler和DAGScheduler,taskScheduler的主要任务是创建task调度池实现task级别的任务调度和联系master进行app注册;DAGScheduler则是面向stage的高层次的调...

weixin_44024821的博客 585

Spark源码分析——Spark整体架构

Spark源码分析——Spark架构常用术语 术语 描述 Application 用户编写的程序。(Driver端的SparkContext、SparkConf和运行在Executors上用户编写的业务逻辑代码即map、reduce、reduceByKey等) Driver 执行用户编写应用程序的main()方法并创建SparkContext Worker 具体运行应用

IWantT0的博客 655

你真的懂Spark吗?手把手带你解析Spark-Submit提交应用程序过程(Spark2.12)

前几篇博客详细解析了Spark的Job触发机制、Spark的DAGScheduler调度机制、Spark的TaskScheduler调度机制、Spark调度器的终端通信SchedulerBackend和Spark的Executor启动,在对这些源码进行分析之后,头脑中十分混乱,对于各个机制的具体执行过程不是十分了解。网上的各种分析博客也写得不是十分清晰,于是就开始了Spark任务提交流程的分析。本博客的Spark版本为2.12,是以Standalone Cluster部署模式为基础进行分析。 Spark.

LMR的博客 4883

Spark 写入hive表解析

摘要:FileOutputCommitter在Spark中提供v1和v2两种文件提交算法。v1版本采用两阶段提交(先写临时目录再移动),存在单线程瓶颈;v2版本直接写结果目录,效率更高但存在数据可见性问题。与Hive集成时,通过临时目录机制保证原子性,Hive采用多线程移动文件提升性能。建议生产环境使用v2算法,其整体流程更高效,特别是在Hive的多线程支持下能有效解决原子性问题,同时保持高性能。

weixin_43839095的博客 1202

Spark Streaming运行流程及源码解析(一)

Spark Streaming运行流程及源码解析(一) 本系列主要描述Spark Streaming的运行流程,然后对每个流程的源码分别进行解析 之前总听同事说Spark源码有多么棒,咱也不知道,就是疯狂点头。 对Spark的使用也就是Spark Streaming使用的多一点,所以就拿Spark Streaming开涮。 源码中的一些类 这里先列举一些源码中的类,大家先预热一下。 Stre...

upupfeng的博客 684
上一篇: Spark Submit流程源码详解(on yarn)
dab-hand
博客等级 码龄7年 10粉丝 5原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值