Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)

深度剖析spark原理

简介

深度剖析源码加图解spark处理数据全流程

spark内核

开篇图

下面是Standalone集群模式的情况,yarn集群也是大同小异

  •  向集群submit一个应用以后,启动一个Application,里面会启动一个Driver进程
  • Driver里面会生成一个sparkContext,每一个action执行都会启动一个job
  • 初始化sparkContext以后会生成一个DAGschedule和一个Taskschedule
  • 然后Driver向Master申请Executor资源
  • Executor申请下来以后会向Driver注册自己的信息
  • DAGschedule根据启动的job生成一个个stage,每一个stage里面是一个taskset
  • Taskschedule把生成的taskset发送到对应的Executor的线程池里面执行
  • 相同stage里面的parition处理是在一个Task里面处理的
  • 一个stage处理完以后Taskschedule就会处理另外一个,直到处理完为止

宽依赖窄依赖图解

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第1张图片

  • 在窄依赖的情况 由于子RDD和父RDD他们是一对一的关系,所以在执行的时候,partition中的数据可以在一个task中执行 。
  • Task有两种,一种是shuffleMaptask一种是ResultTask,中间的操作都是shuffleMaptask,在结束的时候才是ResultTask

spark三种提交模式图解

  • standalone默认(就是spark本身的集群模式,上面已经图解了)
  • yarn-cluster (Driver在集群里面分配资源启动)
  • yarn-client (Driver在提交的机器启动)

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第2张图片

核心类详解

SparkContext

初步认识SparkContext

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第3张图片

  • TaskScheduleImp通过创建的SparkDeployScheduleBackend实现Driver向Master进行注册,还有Executor资源和接收Executor反向注册到Driver的请求
  • 生成的DAGschedule负载对于执行action以后生成的job生成stage,并且把每一部分的stage的任务发送到Executor的线程池进行执行
  • 生成一个SparkUI,端口是4040,内部使用的jetty

sparkContext启动流程详细图解

链接:https://pan.baidu.com/s/1B6_VrF7y8VvsOX6EZ5Caqg 
提取码:yyds 

Master深度剖析

Master主备切换图解原理

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第4张图片

  •  就是在Master的active存活的时候会保存一些信息到hdfs文件系统或者是zookeeper上面,如果Master宕机了,Standby Master就会通知正在处理的Driver和Executor获得他们的存活信息,如果没有存活了重新启动重新分配资源,如果是存活的就给新的Master回复下

在master主从切换完以后处理源码流程图解

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第5张图片

master的注册机制图解和源码剖析

下图是Driver,Worker,Application向Master进行注册

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第6张图片

  •  worker注册到Master的时候,Master先处理掉状态UNKNOWN的Worker,然后保存正在注册的Worker的信息到一个Hashmap中,在用持久化的机制保存到hdfs或者zookeeper,然后执行调度方法
  • 其他的图中很详细的介绍了

下图是master注册application源码分析流程图

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第7张图片

 master的状态改变机制

driver状态改变机制源码剖析

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第8张图片

 exector状态改变机制源码剖析

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第9张图片

master资源调度源码分析(schedule)

  • 它的主要的作用就是,为driver分配资源,还有对application的exector分配资源
  • 为exector分配资源的时候有一个分配算法spreadOutApps,spark.deploy.spreadOut它的默认值为true,也就是默认分配的时候尽量均衡的分配到可用的worker上面,如果为false,那么就是尽量的先把一些worker资源用完在用其他worker的资源
  • 然后就是application利用自己对本身driver的引用,为driver发送自己分配的executor的信息,建立driver和executor之间的联系

部分源码流程

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第10张图片

详细源码流程

链接:https://pan.baidu.com/s/1qnx6CpLWzTGcHpapO42x0w 
提取码:yyds 

总结下:

  • SparkContext初始化的时候会向Master发送一个registerApplication请求,Master在receive接收到注册Application的请求以后,会在Master缓存中加入ApplicationInfo信息
  • 然后就是调度分配资源,如果是yarn模式那么Application中的Driver会在一个调度队列里面等待调度分配资源,如果是其他模式就没有这个等待的操作就会直接启动Driver
  • 分配好Driver的资源以后,开始分配Executor的资源,在Worker上面分配Executor的时候有 一个算法可以进行选择spark.deploy.spreadOut,默认是true就是尽量均衡的分配到可用的worker上面,如果为false就是只有worker上面的资源不能分配的时候才分配到其他的worker上面
  • 分配好Executor以后,由于Application里面有本身对应Driver的Rpc对象,它就会在Executor资源分配完以后,把自己分配到的Executor发送给Driver,这个请求是ExecutorAdded(exec.id, worker.id, worker.hostPort, exec.cores, exec.memory)

Work深度剖析

work启动Driver和Executor原理剖析大概图

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第11张图片

 详细源码流程解读

链接:https://pan.baidu.com/s/1KRLnlaeLuC1cMJQHF2VVOw 
提取码:yyds 

总结启动Driver和Executor的流程:

  • 在初始化SparkContext的时候里面会创建一个TaskSchedulede 方法是SparkContext.createTaskScheduler,根据环境的不同创建不同的StandaloneSchedulerBackend,他是CoarseGrainedSchedulerBackend的一个子类,它里面有一个class DriverEndpoint就是Driver的Rpc引用
  • 在StandaloneSchedulerBackend的start方法里面会创建一个StandaloneAppClient,它与Application注册有关
  • 然后Master接收注册的信息是case RegisterApplication(description, driver),可以看到传入了Application的描述信息还有Driver的信息,说明Driver比Application先创建
  • 然后Driver执行driver.send(RegisteredApplication(app.id, self)),在本身绑定application的信息,还有注册到了哪个Master的信息
  • 然后就是执行资源调度方法schedule(),Master分别执行launchDriver(worker, driver)(这个Driver在等待队列调度是yarn才有的,如果是其他模式是直接启动的没有等待的过程)和launchExecutor(worker, exec)
  • 然后就是到了Worker,receive分别接收case LaunchExecutor,case LaunchDriver,分别为Driver和Executor分配资源
  • 然后就是Work更具对于的状态给Master发送状态改变的信息,执行exitCode = process.get.waitFor()然后根据返回的状态码,worker.send(DriverStateChanged(driverId, finalState.get, finalException))
  • Master接收到case DriverStateChanged,信息以后释放资源等操作
  • 初始化Executor以后,Executor会反向注册到application里面的Driver
  • 然后SparkContext初始化完成,资源分配也完成了

Job触发流程和源码分析

从wordcount开始讲解

object ScalaWordCount {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf()
    conf.setAppName("ScalaWordCount")

    val context = new SparkContext(conf)
    val lineTextRDD: RDD[String] = context.textFile("hdfs://hadoop102:8020/data.txt")
    lineTextRDD.flatMap(line=>line.split(" "))
      .map((_,1))
      .reduceByKey(_+_)
      .foreach(println)

    context.stop()
  }
}

textFile调用的内容 

  • 首先调用的是textFile,里面创建了 一个hadoopFile,然后创建了new HadoopRDD,并且把hadoopConfiguration也就是hadoop的配置文件作为广播变量广播到HadoopRDD分区中
  • 在hadoopRDD里面分区的方法里面有一个很重要的方法getInputFormat(jobConf).getSplits(jobConf, minPartitions),这也就证明了为什么每一个分块的数据发送到一个分区里面
  • 最后得到的数据map(pair => pair._2.toString),因为TextInputFormat读取到的数据是行号,还有对应的行的 信息,我们只要内容就行了。这就是textFile里面包含的内容

reduceByKey的由来

  • 在RDD里面我们发现是没有这个方法的,这是由于RDD使用了隐式装换的原因,在伴生对象里面有一个implicit def rddToPairRDDFunctions,只要作用范围内可以装换,那么就会加入装换操作,而rddToPairRDDFunctions就是返回new PairRDDFunctions(rdd)对于key,value类型数据的操作

执行action操作foreach

  • 在执行action操作里面会调用sc.runJob,然后会调用dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, resultHandler, localProperties.get),rdd就是要处理的东西,这个dagScheduler就是sparkContext初始化的时候创建的。

DagSchedule原理剖析和源码剖析

DagSchedule划分stage的大概流程图

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第12张图片

图解

  • 在reduceByKey的时候会分出几个RDD,第一个是mapPartitionRDD会分组后落盘,中间的ShuffleRDD处理聚合操作 
  • 划分stage的时候,从最后一个RDD开始,一直往前,如果是窄依赖,那么就是划分到一个stage里面,如果是宽依赖那么就划分出一个新的stage,一直循环这样处理,直到处理完最后一个

DAGschedule的stage划分算法详解流程图

链接:https://pan.baidu.com/s/1vyNChLd-VQvN8K8QV5GgLA 
提取码:yyds 

stage划分算法总结

  • 最后一个RDD首先会创建一个finalStage,然后加入到调用栈中,然后开始判断他们的宽依赖还有窄依赖关系,如果是窄依赖就加入栈中,如果是宽依赖那么就创建一个新的stage,新创建的stage叫做ShuffleMapStage
  • 更具得到finalStage的父stage,加入到waitingStages(就是等待要执行的stage里面)
  • 然后在递归调用,获取到第一个RDD为止,
  • 递归到第一个的时候,就开始执行stage0,执行完以后在执行waitingStages里面的stage

stage的task优先位置算法

  • 提交stage以后,也就是执行submitMissingTasks,根据stage的不同初始化出不同的task,除了finalstage以外,其他的都是ShuffleMapTask,finalstage创建的task为ResultTask
  • 初始化task的时候是每一个分区一个task,在一个stage里面的一个partiton公用一个task,在task优先位置算法的时候,首先寻找这个这个RDD的一个parition是否在缓存中有值,如果有那么task就在cache开始执行,然后就是看checkpoint,如果checkpoint里面有值task就先从checkpoint启动(所以这里得到一个结论,找缓存的时候是根据partition的id去找的)

详细源码跟踪

链接:https://pan.baidu.com/s/1hhJnFeDnxq4QAEjaRoI17Q 
提取码:yyds 

TaskScheduler原理和源码剖析

原理流程图解

链接:https://pan.baidu.com/s/1bGncyw5g1PDHi0Kb_DRerg 
提取码:yyds 

  • 由于上面的stage已经得到了task,那么就会调用TaskScheduler,进行Task的提交
  • 在提交之前,会对Task发送到哪个Executor有一个本地化优先执行算法,然后得到Task和Executor和task的对应关系,然后把Task发送到对应的Executor上面去执行

Executor原理源码剖析

在spark里面创建的Executor实际创建的是CoarseGrainedExecutorBackend

Executor大概图解

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第13张图片

代码逻辑图

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第14张图片

 总结:

  • CoarseGrainedExecutorBackend在启动的时候会执行onStart然后向Driver注册自己
  • Driver收到信息以后,回复一条可以注册的信息,然后CoarseGrainedExecutorBackend创建出一个Executor
  • 创建出Executor以后,它就会接收由TaskSchedule发送过来的Task信息,进行反序列化以后,放入自己的cache线程池中进行执行

Task原理和源码剖析

Task大致原理如图

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第15张图片

 详细执行流程图

链接:https://pan.baidu.com/s/1FYYxCwFmv5PK600-5T5L0Q 
提取码:yyds 
总结:

  • 反序列化Task以后,放入TaskRunable里面执行,读取需要的文件还有Jar包
  • 根据runTask不同类,有ShuffleMapTask和ResultTask两种
  • ShuffleMapTask执行的时候会根据广播过来的RDD数据,进行区分,也就是说只处理自己的那一部分partition数据
  • 处理得到partiton的数据为Mapstatus保存在BlockManage,而且输出的分区格式是Hashpartitioner
  • 得到数据以后,就会向Driver汇报执行Task的信息,发送的请求是statusUpdate,Driver通过receive方法接收,通过返回的Task执行的状态判断是在Taskset正在执行的Task里面移除,还有报错以后重新提交Task

Shuffle原理剖析和源码剖析

什么情况下会出现shuffle?

reduceByKey,groupByKey,sortByKey,countByKey,join,cogroup

shuffle的问题及改进

Spark在1.1以前的版本一直是采用Hash Shuffle的实现的方式,到1.1版本时参考Hadoop MapReduce的实现开始引入Sort Shuffle,在1.5版本时开始Tungsten钨丝计划,引入UnSafe Shuffle优化内存及CPU的使用,在1.6中将Tungsten统一到Sort Shuffle中,实现自我感知选择最佳Shuffle方式,到最近的2.0版本,Hash Shuffle已被删除,所有Shuffle方式全部统一到Sort Shuffle一个实现中。下图是spark shuffle实现的一个版本演进

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第16张图片

Hash Shuffle v1

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第17张图片

每一个task都对应每一个分区生成一份文件

Hash Shuffle v2

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第18张图片

每一个core为单位,产生对应的分区文件 

Sort Shuffle v1

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第19张图片

每一个Task产生 一份文件,不过会有一个index文件标识分区段 

shuffle源码分析

 链接:https://pan.baidu.com/s/10_bK-nefAH8sPHj9QQJDjg 
提取码:yyds 
总结:

  • ShuffleMapTask在执行的时候就会有落盘的操作
  • ShuffleMapTask开始的时候会先得到一个shuffleManage,由于在之前的Hash删除了,所以剩下的只有SortShuffleManage
  • SortShuffleManage会根据不同的环境得到不同的write对象,如果没有map预聚合的情况,并且下游的partition数量小于默认的200,spark.shuffle.sort.bypassMergeThreshold,可以设置这个值,满足这两个条件就会创建BypassMergeSortShuffleHandle,然后他会得到BypassMergeSortShuffleWriter,它是一种不用排序的shuffleWrite,它的原理和Hash Shuffle v2很像
  • 如果不能序列化,也不满足上面的条件,就是SortShuffleWriter,这就是Sort Shuffle v1的情况
  • 上面是写的过程,然后读数据的过程是ShuffledRDD,它的compute就是可以找到文件句柄读取文件操作

BlockManage原理

基本架构图解

CacheManager原理

基本架构

Spark3.x入门到精通-阶段三(深度剖析spark处理数据全流程)_第20张图片

CheckPoint原理和源码剖析

基本原理

你可能感兴趣的:(spark,大数据)