参考:http://blog.youkuaiyun.com/slq1023/article/details/50816669
1. Spark内核架构
1.1 spark runtime 流程示意图
1.2 driver、SparkContextspark、executor等概念
application = driver + executor
driver部分代码:Sparkconf + SparkContext
val conf =new SparkConf()
conf.setAppName("...")
conf.setMaster("...")
val sc = new SparkContext(conf)
SparkContext创建的过程中做了很多内容,包括DAG Scheduler(一个应用程序默认只有一个DAG
Scheduler)、TaskScheduler、SchedulerBackend、SparkEnv。注:driver是以sparkContext为核心的,可以理解为driver就是sparkContext
1.3 spark cluster 流程示意图
Executor是运行在Worker节点上的为当前应用程序而开启的一个进程里面的处理对象,这个对象负责了Task的运行,通过线程池中的线程并发执行和线程复用的方式,线程池中的每一个线程可以运行一个任务,任务完成后回收到线程池中进行线程复用。
由于CPU Cores的个数是有限的,如果只开启一个Executor,当任务比较大时内存易OOM。这时最好分成几个不同的Executor。
=> 不会。worker会不断向Master发的心跳,但内容只有worker ID。是用来判断Worker是否活着。
那master怎么知道各节点的资源信息?
=> 分配资源的时候就已经知道了。应用程序在向Master注册时,注册成功后master就会分配资源,分配时就会记录资源,所有的资源都是Master分配的,所以Master当然知道各节点的资源信息了。
只有当Worker出现故障时才会向Master汇报资源情况。
JOB里面是一系列的RDD及作用在RDD的各种operation操作,collect就是一个Action,会触发一个作业。wordCountOrdered就是一系列的RDD及对RDD的操作。包括map、flatMap、TextFile,每一步都会至少产生一个RDD。TextFile就会产生hadoopRDD 和MapPartitionsRDD。
JOB都是由Action触发的,触发时前面有一系列的RDD。
action不会产生RDD,只会导致RunJOB。
action前是RDD,是transformation级别的,是lazy级别的执行方式。
如果后面的RDD对前面的RDD进行回溯时是窄依赖的话,就会在内存中进行迭代,这是Spark快的一个很重要的原因。
spark快不仅是因为基于内存。调度,容错才是Spark的精髓的基本点。
窄依赖有一个Range级别,即依赖固定个数的父RDD。所谓固定个数是说不会随着数据规模的扩大而改变。
依赖构成了DAG。如果是宽依赖DAG Scheduler就会划分Stage,Stage内部是基于内存迭代的,当然也可以基于磁盘迭代。
stage内部计算逻辑完全一样,只是计算的数据不同。
任务(Task)就是计算一个数据分片的,数据分片:例如从HDFS上读取数据时默认数据分片就是128MB。
※ 一个数据分片是否精准地等于一个Block的大小(默认128MB)?
=> 一般情况下都不等于,因为最后一个分片会跨两个Block。
1.4 通过spark historyserver UI查看
2. SparkDAG概念
Spark内核会在需要计算发生的时刻绘制一张关于计算路径的有向无环图,也就是DAG。
有了计算的DAG图,Spark内核下一步的任务就是根据DAG图将计算划分成任务集,也就是Stage,这样可以将任务提交到计算节点进行真正的计算。Spark计算的中间结果默认是保存在内存中的,Spark在划分Stage的时候会充分考虑在分布式计算中可流水线计算(pipeline)的部分来提高计算的效率,而在这个过程中,主要的根据就是RDD的依赖类型。根据不同的transformation操作,RDD的依赖可以分为窄依赖(Narrow Dependency)和宽依赖(Wide Dependency,在代码中为ShuffleDependency)两种类型。窄依赖指的是生成的RDD中每个partition只依赖于父RDD(s) 固定的partition。宽依赖指的是生成的RDD的每一个partition都依赖于父 RDD(s) 所有partition。窄依赖典型的操作有map, filter, union等,宽依赖典型的操作有groupByKey, sortByKey等。可以看到,宽依赖往往意味着shuffle操作,这也是Spark划分stage的主要边界。对于窄依赖,Spark会将其尽量划分在同一个stage中,因为它们可以进行流水线计算。
至于以上一些shuffer过程建议大家多看看spark官网会比较好点。
本文详细介绍了 Spark 的核心架构,包括 Driver 和 Executor 的角色与功能,SparkContext 的创建过程,以及 Job 的触发机制。深入探讨了 DAGScheduler 如何划分 Stage 和 TaskScheduler 如何调度任务,同时分析了不同依赖类型对计算的影响。
3076

被折叠的 条评论
为什么被折叠?



