第13讲:Spark 内核构架
前言:
我们为什么要这样写程序?为何要这样运行程序?以及程序运行背后发生了什么?
关于Spark Runtime
Driver 是运行程序的时候具有main 方法并且创建了sparkcontext 的环境对象。Dirver里面运行application 的main方法(函数),并且在运行main函数的时候,一定创建sparkcontext对象。Sparkcontext 是我们通往集群的唯一通道,是开发者使用集群的各种功能的唯一通道。
在dirver中的main 方法中创建的sparkcontext ,他本身是整个程序运行调度的核心(不是指资源调度),里面会有高层调度器DAGScheduler 将整个作业划分成几个小的阶段,底层调度器TaskScheduler 每个阶段里的任务该怎么处理 。还有Schedulerbackend 管理整个集群中为这个当前的程序分配的计算资源(即executor)。
我们默认讲解的内容都是基于spark的 standalone模式下,standalone 模式下spark 比在yarn 和mesos 好很多,不需要其他的东西。 如果是基于spark来处理数据,基本一个spark框架就可以,不必要使用yarn或者mesos 等。(如果掌握了standalone模式,掌握yarn或者mesos 是没有问题,因为他们80%都是类似的)
Sparkcontext 在创建 DAGScheduler、TaskScheduler、Schedulerbackend 的同时还会向master 注册当前程序。如果注册没有问题的话,master 会给这个程序分配资源,然后根据action 触发job,job里面有一系列 RDD ,从后往前推发现是宽依赖的话,就划分不同的stage。Stage划分完成之后,stage 提交给底层的调度器TaskScheduler,TaskScheduler拿到这个任务的集合。因为一个stage内部都是完全计算逻辑一样的任务,只不过是计算的数据不同。底层调度器就会根据数据的本地性,将任务分配到executor上去执行。executor 在任务运行结束或者出状况的时候,肯定要想driver 汇报。最后运行完毕之后,关闭sparkContext,同时他创建那些对象也要关闭掉。
Driver应用程序运行时候的核心,他负责了整个作业的调度,同时会向master申请资源完成具体作业的工作过程。那什么叫应用程序?应用程序就是用户编写的spark代码打包后的jar包和相关的依赖,它里面driver功能的代码和分布在集群中多个节点的executor 代码。Driver 是驱动executor去工作,executor 内部是线程池并发的去处理数据分片的。
Driver部分的代码就是sparkconf +sparkcontext 部分。 SparkContext在创建的时候做了很多的内容,包括DAGScheduler、TaskScheduler、Schedulerbackend。Spark-env 等。(一个程序默认有一个DAGScheduler)
Textfile 、flatmap ,map 可以产生很多RDD 是具体的业务实现,就是executor中具体要执行的代码。
所以一个应用程序包含 :Driver端的代码,分布在集群中多个节点上executor的代码。所有的业务逻辑都是在具体的集群worker 上的executor 上执行(前提代码要发送到集群上)。
从上图可以看出整个应用程序分为driver Program Executor上并行运行的task任务。
什么叫executor?是运行在worker节点上的为当前应用程序开启进程里面的处理对象。这个对象负责具体的task 运行,是通过线程池并发运行和线程复用的方式。Spark在一个节点上为当前的程序开启一个jvm进程,jvm进程是线程池的方式,通过线程处理具体的task任务。Executor 是进程里面的对象。 一个worker默认为当前的应用程序开启一个executor(可以配置多个)。
Executor靠线程池中的线程运行task的时候,肯定会去磁盘或者内存中读写数据。每个application都有自己独立的一批Executor。
Cluster Manager 是集群中获取资源的web服务。在spark最初的阶段没有yarn的模式也没有standalone模式,资源管理服务是mesos,后来增加了yarn,后来为了推广普及产生了standalone。 最重要的特征:spark的application的运行不依赖于Cluster Manager。也就是说 spark 的application注册给master,如果注册成功,master提前给application分配好了资源,运行过程中根本不需要cluster manager 的参与。cluster manager是可插拔的。这种资源的分配方式是粗粒度的资源分配方式。
具体的集群中具体的工作,除了 Cluster Manager、master、资源分配器,这些都是处于主节点。什么worker?worker是集群中任何可以运行application具体textfile、flatmap、map、filter、reducebykey等等这些操作代码的节点。woker上是不会运行程序代码的,worker是管理当前节点内存、cpu 等资源的使用状态,他会接收master 分配资源(即executor)的的指令,会通过ExecutorRunner启动一个新进程,进程中里面有executor。
也就是说Cluster Manager 是项目经理,worker是工头,项目经理(Cluster Manager)会管理很多工头(worker),工头下面有很多工人(executor)。
所以Worker管理当前节点的计算资源(主要是cpu、内存),并接收master的指令,来分配具体的计算资源(在新的进程中分配)。要分配一个新的进程做计算的时候,ExecutorRunner 相当于一个代理,管理具体新分配的进程,也监控我们具体的Executor所在进程运行的状况。其实就是在ExecutorRunner中远程创建出新的进程的。Woker是一个进程,不会向master汇报当前机器的cpu和内存等信息。Worker 发心跳只有workerid。应用程序注册成功的时候,master会给应用程序分配资源,分配的时候都会记录资源。如果中间Executor lost的情况,worker要向master汇报然后动态的调整下资源。
作业(job):包含了一系列的task 的并行计算。在spark中一般会由action(例如saveastextfile)触发。在job里面是一系列的RDD 和作用于RDD 的各种操作。 Job一般是有action 触发,前面会有一系列的RDD,但是action不会产生RDD,会导致runjob。
例如 collect前面的RDD 是transformation级别的不会立即执行,从后往前推。回溯时如果是窄依赖在内存中迭代。Spark只所以快决不是因为基于内存,最基本的原因是调度,容错等。
依赖分为窄依赖和宽依赖。例如现实生活中,工作依赖一个对象,是窄依赖,依赖很多对象,是宽依赖。 窄依赖除了一对一,还有range级别的依赖,依赖固定的个数,随着数据的规模扩大而改变。 比如依赖3个父RDD 的partiton,1p的数据是这样,1t 的数据也是这。
如果是宽依赖,DAGscheduler会划分成不同的stage,stage内部是基于内存迭代的,也可以基于磁盘迭代,stage内部计算的逻辑是完全一样的,只是计算的数据不同而已。具体的任务就是计算一个数据分片的,一个partition 的大小是128M。一个partition不是完全精准的等于一个block 的大小,一般最后一条记录跨2个block。
这里有2个stage,因为reduceBykey 会产生shuffle(宽依赖)。 Stage0 内部的TextFile、flatmap、map 默认基于内存迭代,如果内存不够会基于磁盘迭代。这是一个job,因为进行collect操作是个action,触发作业,从后往前推。每个stage 内部都有一系列的任务,我们看下第一个stage。
总共有88个任务,上图蓝色方框内清楚的告诉我们运行了哪些代码。在具体运行时stage内部没有sparkContext 和SparkConf。因为sparkContext 为核心是driver层面。
任务都是运行在Executor中。默认每台机器为当前的程序分配一个executor,这里有4个worker,所以有4个executor。可以看到每个Executor 上 的任务运行情况。 Worker 本身就是管理Executor的,
上图显示tasks 运行在不同的机器上。
重点说明:一个Application 可以有多个job,因为可以有不同的action。一般一个action 对应一个job, 例如 checkpoint、sort等操作会触发多个job。
Spark的程序的运行有2种模式:Client、Cluster。 默认情况下建议使用client模式,此模式下可以看到更多的交互性信息,及运行过程的信息。此时要专门使用一台机器来提交我们的spark程序, 配置和普通的worker配置一样,而且要和cluster manager 在同样的网络环境中,因为要指挥所有的worker去工作,woker里的线程要和driver不断的交互。
由于Dirver要驱动整个集群, 频繁的和所有为当前程序分配的Executor 去交互,频繁的进行网络通信,所以必须在同样的网络中。
也可以指定 deploy model 为cluster,这样真正的divrer 会在worker中的一台机器,是有master决定的。master为你分配的第一个Executor 就是dirver级别的Executor。不推荐学习、开发、使用cluster,因为无法直接看到一些日志信息, 可以看log。但是最交互式终端看到更多的信息是最好,最方便的方式。
建议使用client方式。 内核架构图如下所示
原文:http://blog.csdn.net/a11a2233445566/article/details/54600288