本博文的主要内容如下:

  1、通过案例观察Spark架构

  2、手动绘制Spark内部架构

  3、Spark Job的逻辑视图解析

  4、Spark Job的物理视图解析 

 1、通过案例观察Spark架构

  spark-shell中,默认情况下,没有任何的Job。

  从Master角度讲:

    1、管理CPU、MEM等资源(也考虑网络)

   2、接收Driver端提交作业的请求,并为其分配资源(APPid等)

    注:spark默认是粗粒度,即spark作业提交的时候就会为我们作业分配资源,后续运行的过程中一般使用已分配的资源,除非资源发生异常需要重新分配。

 从Worker角度讲:

     Worker进程负责当前worker节点上的资源的使用。从分布式的节点架构讲Spark是Master/Slave分布式的,从作业的运行架构来讲主要分为Driver和众多的Worker,而从集群静态部署来讲分为Master和Worker。

              

                      图1 Spark逻辑执行

  

运行作业

  在spark的安装目录下的bin下,  执行 ./spark-shell --master spark://Master:7077

  此时web控制台http://Master:8080,多了一个Running Applications ,该Application有Master分配的ApplicationId和由Master的分配的资源(MEM、CPU的Cores等),而分配的Cores的个数和MEM在spark.env.sh中做了配置,Spark-shell中默认情况下没有任何的job,但是在Standalone模式中默认为粗粒度的资源分配模式,提交应用程序后,Master已经进行了粗粒度的资源分配。

                    图2 作业运行job视图

  从图2看出在作业运行的端口中可以看出Cores是32,Mem是4G是在Spark-env.sh中配置的,standalone模式spark-shell只是提交了一个程序,没有做任何事。默认情况下每个Worker上启动一个ExecutorBackend进程,一共有5个Executor。driver驱动整个应用程序的运行,一个Worker上可以配置多个ExecutorBackend进程,例如在只有一个Executor的时候,CPU利用率不高的情况,只有应用程序关闭Executor线程池才会stop。

应用程序在提交的时候会进行注册并由Master分配id和计算资源,无论一个应用程序中有多少的Action导致的作业在运行,也不会产生资源冲突的情况,因为作业运行的资源实际上是在粗粒度的方式下在程序注册的时候分配好的,多个job可以采取资源复用和排队执行的方式运行完应用程序。

默认的资源分配方式在每个Worker上启动一个ExecutorBackend进程,且默认情况下会最大的占用CPU和MEM,若不加限制,集群上除了Spark还有其他程序的话,Spark运行就会占用最大的资源,给人一种Spark很占内存的感觉,若有多套计算框架,就需要资源管理器yarn或者mesos。

  1. root@Worker1:~#jps
  2. 3920 Worker
  3. 3244 DataNode
  4. 2565 jps
  5. 6455 CoarseGrainedExecutorBacken

  

  采用Client的方式提交应用程序,让driver运行在Client的机器上,也可以采用Cluster的方式提交到集群中,使用spark-shell运行程序会在Worker上多了进程CoarseGrainedExecutorBackend进程,默认情况下Worker节点为程序分配一个Executor,而CoarseGrainedExecutorBackend进程里有Executor,Executor会通过并发线程池并发执行的方式执行Task。

  1. scala> sc.TextFile("/library/wordCount/input/Data").flatMap(_.split("")).map(word => (word,1)).reduceByKey(_+_,1).map(pair => (pair._2 , pair._1)).sortByKey(false).map(pair = > (pair._2,pair._1)).collect

  运行程序,广告点击排名,在ReduceByKey(_+_,1)进行了全局单词的排序,然后在ReduceByKey中指定并行度为1,因为只有一个作业collect,DAG如下:

                      

                      图3 DAG视图

  

  从上面运行的job可以看出一个job产生了3个stage(数据在Stage内部是pipeline流过去的,依次是HadoopRDD、MapPartitionRDD、MapPartitionRDD、ShuffledRDD...),两个shuffledRDD,因为shuffledRDD是宽依赖(每个父RDD都被子RDD使用),因为遇到宽依赖就断开,遇到窄依赖就把当前的RDD加入该Stage中,所以形成三个stage。

             

                                                    图4

  从Stage中可以看出,一共有88个Task,因为这里有88个文件且每个文件大小小于HDFS默认的文件块BLOCK大小128MB,每个文件就是一个Partition,共有88个Partitions,而默认情况下一个Task对应执行一个Partition,所以就有88个Task,而每个Task都运行在Executor中,并发复用执行。每个Worker运行多少个Task,主要由于数据本地行,数据在哪尽量在哪儿排队并发运行,以此减少网络传输IO,减少通信频率。

                                图5

  可以从图5看出一共有4个Executor,每个Worker上一个Executor进程,因为默认情况下每个Worker上启动一个Executor进程(一个CoarseGrainedExecutorBackend进程一一对应一个Executor进程,而CoarseGrainedExecutorBackend是进程级别的,Executor是计算资源级别的,因为其内部有线程池),并最大化利用当前Worker上的内存和CPU,这点前面已经提到,并且每个Executor运行不同个数的Task。

需要注意的是:一次性最多在Executor中能运行多少个并发的任务task取决于当前节点Executor中Cores数量,在实际运行的时候哪个task执行完成,就会将资源回收到线程池中进行覆用,对于一次没法全部运行的任务,就会形成task排队的情况,为了应对这种情况,优化的方法(避免oom),指定多个Executor线程池,增加分片数量,每个分片中的数据就小,所以减少OOM情况,获取更多的MEM和资源,但前提是我们的Spark运行在拥有其他大数据框架的集群中。

下面运行有Cache的情况(Cache后不同有算子,Cache后Storage中):

  1. scala>val cached = sc.TextFile("/library/wordCount/input/Data").flatMap(_.split("")).map(word => (word,1)).reduceByKey(_+_,1).map(pair => (pair._2 , pair._1)).cache

运行完成后产生一个新的job

                                图 6 Storage视图

  从图6看出,由于进行了Cache操作,所以讲ShuffledRDD Cache到了内存中,且只有一个副本,因为数据不足128MB,所以只有一个Partition,对应一个Task,这里Executor在Worker2上,那么作业运行在Worker2上,充分说明了运行任务的时候基于数据本地性。

下面测试在ReduceByKey的时候,不传入第二个参数,即不指定作业运行的并行度,分别运行:

  1. scala>val cached = sc.TextFile("/library/wordCount/input/Data").flatMap(_.split("")).map(word => (word,1)).reduceByKey(_+_).map(pair => (pair._2 , pair._1)).cache
  2. scala>cached.map(pair = > (pair._2,pair._1)).collect

             

                            图7 作业运行DAG视图

  从图7 反应的Stage的DAG可以看出Stage8已经kipped了,是Application内部进行的优化,查看job得知本次作业运行产生了88个并行度,即88个Partition,因为不指定并行度的话,作业会继承并行度。

注:如果我们的Spark集群只是作为唯一的计算框架,没有其他计算框架,为了应对oom,需要增加分片数量,每个分片运行的数据减小。

任务在运行前具体分配给谁主要取决于数据本地性(有些机器分配的多,也有些分配的少)!

  

 2、手动绘制Spark内部架构

    无

  3、Spark Job的逻辑视图解析

                                          图8 Spark执行逻辑图

  

(Worker NODE上是Worker进程,其中有Executor Process句柄,管理当前节点上的计算资源接受Master的管理)

从总体而言,spark在集群启动的时候,有个全局的资源管理器Master,负责整个集群资源的管理以及接受程序提交并为程序分配资源,而每个Worker节点上都一个Worker process来管理当前机器上的计算资源,当应用程序提交的时候,Master就会为我们提交的应用程序在每个节点上默认分配一个CorseGrainedExecutorBackend进程,该进程默认情况下载不对MEN和CPU进行限制,会最大化的应用当前机器的MEN和CPU,当Driver实例化没有问题的时候,Driver本身会进行作业的调度来驱动CorseGrainedExecutorBackend中的Executor中的线程,来具体并发执行task,这也是Spark并发执行的过程。

而从CorseGrainedExecutorBackend的角度来看是Worker Process来管理当前节点上的MEM 和CPU,但是真正管理资源的是Master,Worker Process只是走个形式,因为我们的CorseGrainedExecutorBackend进程是被Worker Process分配的,实质上是通过Master来管理Worker节点的资源。

每个Worker上包含一个或者多个ExecutorBackend进程,而每个ExecutorBackend中包含一个Executor对象,该对象拥有一个线程池,而每个线程又可以覆用多个Task任务。

从DAG逻辑角度来看数据在Stage内部是pipeline流过去的,因为有两次ShuffledRDD,所以job被划分成3个Stage。

从Hadoop的MapReduce角度看stage0上stage1的mapper;而stage1上stage0 的mapper;stage1上stage2 的mapper;而stage2上stage1 的mapper,我们可以将Spark看做一个MapReduce的更加具体的实现。

扩充:

a)Application中由于不同的Action产生若干job;

b)每个Job中都会至少有一个Stage;

c)每个Stage内部的TaskSet一定是在Executor中执行的。

 

 4、Spark Job的物理视图解析 

      无

感谢下面的博主:

http://bbs.pinggu.org/thread-4631944-1-1.html  

Spark 概念学习系列之从spark架构中透视job(十六)的更多相关文章

  1. Spark RDD概念学习系列之细谈RDD的弹性(十六)

    细谈RDD的弹性  所谓,弹性,是指在内存不够时可以与磁盘进行交换. 弹性之一:自动的进行内存和磁盘数据存储的切换   弹性之二:基于Lineage(血缘)的高效容错   弹性之三:Task如果失败会 ...

  2. Hadoop概念学习系列之常见的分布式文件系统(二十六)

    常见的分布式文件系统有,GFS.HDFS.Lustre .Ceph .GridFS .mogileFS.TFS.FastDFS等.各自适用于不同的领域.它们都不是系统级的分布式文件系统,而是应用级的分 ...

  3. Hadoop HBase概念学习系列之HBase里的时间戳(二十六)

    HBase集群要求每个节点的时间必须同步.HBase对于节点的时间扭曲(time skew)容忍度很低(这和HDFS是不一样的). 这主要是因为HBase需要使用系统时间来产生时间戳.如果系统时间不同 ...

  4. Spark 概念学习系列之从物理执行的角度透视spark Job(十七)

    本博文主要内容:  1.再次思考pipeline 2.窄依赖物理执行内幕 3.宽依赖物理执行内幕 4.Job提交流程 一:再次思考pipeline 即使采用pipeline的方式,函数f对依赖的RDD ...

  5. Spark 概念学习系列之Spark基本概念和模型(十八)

    打好基础,别小瞧它! spark的运行模式多种多样,在单机上既可以本地模式运行,也可以伪分布模式运行.而当以分布式的方式在集群中运行时.底层的资源调度可以使用Mesos或者Yarn,也可使用spark ...

  6. Spark 概念学习系列之Spark 多语言编程

    不多说,直接上干货! Spark 同时支持Scala.Python.Java 三种应用程序API编程接口和编程方式, 考虑到大数据处理的特性,一般会优先使用Scala进行编程,其次是Python,最后 ...

  7. 【CHRIS RICHARDSON 微服务系列】微服务架构中的进程间通信-3

    编者的话 |本文来自 Nginx 官方博客,是微服务系列文章的第三篇,在第一篇文章中介绍了微服务架构模式,与单体模式进行了比较,并且讨论了使用微服务架构的优缺点.第二篇描述了采用微服务架构的应用客户端 ...

  8. 从spark架构中透视job

    本博文的主要内容如下: 1.通过案例观察Spark架构 2.手动绘制Spark内部架构 3.Spark Job的逻辑视图解析 4.Spark Job的物理视图解析 1.通过案例观察Spark架构 sp ...

  9. Spark 概念学习系列之Spark存储管理机制

    Spark存储管理机制 概要 01 存储管理概述 02 RDD持久化 03 Shuffle数据存储 04 广播变量与累加器 01 存储管理概述 思考: RDD,我们可以直接使用而无须关心它的实现细节, ...

随机推荐

  1. 很棒的git和python学习网站

    很棒的git和python学习网站:http://www.liaoxuefeng.com/ 博主名叫廖雪峰

  2. C# worksheet设置Excel样式

    1.例子导出Excel的样式 样式代码 public void Exportdatagridviewtoexcel(string Textname) { SaveFileDialog savedial ...

  3. webform Response的一些成员

    1. Response.BufferOutPut,关闭缓冲区. 2. Response.Flush,一次性把缓冲区的内容释放出来. 3. Response.Clear,清空缓冲区. 4. Respon ...

  4. 快速了解“云原生”(Cloud Native)和前端开发的技术结合点

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 后端视角,结合点就是通过前端流控缓解后端的压力,提升系统响应能力. 从一般意义理解,Cloud Native 是后端应用的事情,要搞的是系统解耦.横 ...

  5. ueditor的bug

    1)过滤script style标签ueditor.all.jsallowDivTransToP:false ueditor.config.js,allowDivTransToP:false //允许 ...

  6. python创建virtualenv虚拟环境

    pip install virtualenv virtualenv env_py36_crawl env_py36_crawl\Scripts\activate deactivate pip free ...

  7. selenium定位元素提示‘元素不可见’问题解决方法

    最近在使用selenium的过程中发现有元素能够在页面中查找到,但是pycharm中运行时始终报错element not visible,于是使用如下方法成功解决问题. 1.driver.find_e ...

  8. P2252 取石子游戏 威佐夫博弈

    $ \color{#0066ff}{ 题目描述 }$ 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子:二是可以在两堆 ...

  9. iOS的本地推送删除不了解决方法

    最近在研究苹果推送,当测试本地推送的时候,发现一个问题,就是一旦你添加了一个本地推动的通知,当你修改代码,删除应用,当你再次运行app,它还是会在横幅上面弹出推送,尼玛怎么搞都删除不了,近乎崩溃了,开 ...

  10. 获取 stoken 或者id MVC写法

    //获取地址栏 painting_idvar painting_id = "{$_GET['painting_id']}"; var stoken = "{$_SESSI ...