2151 2

第23课:从物理执行层面深度剖析Spark中Job的执行内幕 [推广有奖]

  • 1关注
  • 8粉丝

硕士生

34%

还不是VIP/贵宾

-

威望
0
论坛币
305 个
通用积分
0
学术水平
5 点
热心指数
14 点
信用等级
2 点
经验
22942 点
帖子
73
精华
0
在线时间
135 小时
注册时间
2016-2-27
最后登录
2016-9-11

相似文件 换一批

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

本期内容:

1、再次思考pipeline

2、窄依赖物理执行内幕

3、宽依赖物理执行内幕

4、Job提交流程



一、再次思考pipeline

即使采用pipeline的方式,函数f对依赖的RDD中的数据集合的操作也会有两种方式:

1.f(record):即函数f作用于集合中的每一条记录,每次只作用于一条记录;

2.f(records):即函数f一次性作用于集合中的全部数据;


spark采用的是第一种方式,原因在于:

(1).无需等待,可以最大化的使用集群的计算资源。我们可以这样理解:每次function只作用于集合中的每一条记录,这条记录计算完毕后,然后再开始计算下一条;这样做的好处就在于无需等待父RDD中的所有的记录都出结果后才开始计算,这样就节省了时间,从整体上提升了集群计算资源的利用率。

(2).减少OOM的发生

(3).最大化的有利于并发。这点主要说明的是利用Executor对象里面的线程池来并发执行Task.

(4).可以精准的控制每一个partition本身(Dependency)及其内部的计算。

(5).基于lineage的算子流动式和函数式编程,节省了中间结果的产生并且可以最快的恢复;我们以如下的数据流视图为例来说明,如图1所示:

K[9P1N)67U)KRY1TQCUN%7U.png

图1

在图1中,RDD C ,RDD D,RDD F在stage2内部,由于下一个RDD每次只计算一个Record,所以C上的Record准备好之后直接流给D,D就流给F,F把这个Record计算完之后,接着计算下一个Record;从这个角度来看,这就是算子在流动,而且没有中间结果。同时由于是在一个stage内部进行pipeline,所以不会增加网络通信。



二、思考Spark job具体的物理执行

Spark Application 里面可以产生一个或者多个job,例如spark-shell默认启动的时候,内部就没有job,其只是作为资源的分配程序,可以在里面写代码产生若干个job,普通程序中一般而言可以有不同的Action,每一个Action一般也会触发一个job;而在一些特殊情况下,一些action操作又会触发其他的action,但它并不会触发一个job;

Spark是MapReduce思想的一种更加精致和高效的实现,MapReduce有很多具体不同的实现。例如Hadoop中的MapReduce基本的计算流程如下:

首先是以JVM为对象的并发执行的Mapper,Mapper中的map的执行会产生输出数据,输出数据会经过Partitioner指定的规则放到Local FileSystem中,然后再经由Shuffle,Sort,Aggregate变成Reduce中的输入,执行reduce产生最终的执行结果;Hadoop Mapreduce执行的流程虽然简单,但是过于死板,尤其是在构造复杂算法(迭代)时候非常不利于算法的实现,且执行效率极为低下。

    Spark算法在构造和物理执行时最基本的核心是:最大化pipeline。因为pipeline越多的话,数据复用就越好,这是由于pipeline是基于内存的,当然如果出现内存空间不足的情况,pipeline也可以部分基于磁盘。

       因此基于pipeline的思想,数据被使用的时候才开始计算;我们可以从以下三个方面来理解:

(1)从数据流动的视角来说,是数据流动到计算的位置。实质上从逻辑的角度来看,是算子在数据上流动!因为从人思考的角度来考虑,对数据怎么进行处理,这就是所谓的算子,而处理一般是有多个步骤的,这就构成了算子的第一步,第二部,第三步,第四部,这样就是算子在数据上流动;

(2)从算法构建的角度而言:肯定是算子作用数据,所以是算子在数据上流动;

(3)从物理执行的角度而言:是数据流动到计算的位置,方便系统最为高效地运行!


对于pipeline而言,数据计算的位置就是每个stage中最后的RDD;由此可知一个内幕:每个stage中除了最后一个RDD算子是真实的以外,前面的算子都是假的。我们可以从如下两个方面来理解:

(1)  假设一个Stage中有5000个步骤,实际上,只有第5000个步骤需要结果,因为第5000个步骤需要计算下,然后将结果放到磁盘中供下一个stage使用;所以此时会进行算子合并,将5000个步骤的算子合并为一个算子;又由于前面4999个步骤都是lazy级别的,当第5000个步骤触发action操作时,前面的步骤才会依次执行。

(2)  JVM进程并不知道什么是RDD,RDD只是我们自定义的应用逻辑;从这点来看,也印证了我们上面所说的结论。


由于计算的Lazy特性,导致计算从后往前回溯,形成Computing Chain,导致的结果就是需要首先计算出具体一个Stage内部左侧的RDD中本次计算依赖Partition.但这只是从逻辑思考的结果,在计算真正发给executor之前,所有的算子都已经合并成了一个.假设你有5000个步骤,在实际执行的时候,还是按照顺序从第一个步骤开始执行,但是在线程中执行的时候,它就是一个函数而已。


三、窄依赖的物理执行内幕

一个stage内部的RDD都是窄依赖,从逻辑上看,窄依赖计算本身是从Stage内部最左侧的RDD开始立即计算的,根据Computing Chain ,数据从一个计算步骤流动到下一个计算步骤,依次类推;直到计算到Stage内部的最后一个RDD来产生计算结果。

     Computing Chain 的构建是从后往前回溯构建而成,而实际的物理计算则是让数据从前往后在算子上流动,直到流动到不能再流动为止,才开始计算下一个Record.因此可知:后面的RDD对前面的RDD的依赖虽然是Partition级别的数据集合的依赖,但是并不需要父RDD把Partition中所有的Records计算完毕后才整体往后流动数据进行计算,这就极大的提高了计算速率。



四、宽依赖物理执行内幕

必须等到依赖的父stage中的最后一个RDD把全部数据彻底计算完毕才能够经过shuffle来计算当前的Stage。我们以图2的数据流视图为例:

MY5V8R]F)VA8XGKBL9N(1QS.png

图2

在图2中,stage3依赖于stage1和stage2,此时stage3肯定不能对依赖的stage1和stage2算一条,然后就把算好的数据拿过来,因为要进行shuffle操作,只有等依赖的父Stage中所有RDD都计算完毕后,才能拿到数据。我们可以从常理上思考,例如进行groupByKey,如果父Stage中的数据都没有计算完毕,我们是无法对数据进行分组的!同时由于shuffle是一个高风险的动作,所以在开发应用程序时,应尽量减少宽依赖代码。


每个RDD都会有getDependency,其具体负责RDD之间的数据依赖,而compute负责接收父RDD传过来的数据流的record,然后进行计算,最后输出record,由于是基于record计算,所以它是一条一条的。



注:本学习笔记来自DT大数据梦工厂


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Spark SPAR Park job SPA Spark scala DT_Spark 大数据

已有 1 人评分经验 论坛币 收起 理由
daazx + 40 + 10 精彩帖子

总评分: 经验 + 40  论坛币 + 10   查看全部评分

本帖被以下文库推荐

沙发
lzguo568 在职认证  发表于 2016-6-10 15:06:54 |只看作者 |坛友微信交流群

使用道具

lzguo568 发表于 2016-6-10 15:06

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-19 13:18