一、再次思考pipeline
即使采用pipeline的方式,函数f对依赖的RDD中的数据集合的操作也会有两种方式:
f(record),作用于集合的每一条记录,每次只作用于一条记录
f(records)一次性作用于集合的全部数据
spark采用的是第一种方式,原因:
无需等待,可以最大化的使用集群的计算资源;
减少oom的发生;
最大化的有利于并发(限制它并发执行);
可以精准控制每一个partition本身(Dependency)依赖关系及其内部的计算(compute);
基于lineage的算子流动式函数式编程,节省了中间结果的产生,并且可以最大的恢复;
疑问:会不会增加网络通讯:当然不会,因为pipeline在一个stage内。
二、思考spark job具体的物理执行
Spark application里面可以产生1个或者多个job,例如spark-shell默认启动的时候内部就没有job,知识作为资源的分配程序,可以在里面写代码产生若干个job,普通程序中一般而言可以有不同的action,每个action一般也会触发一个job。(有些action会触发其他action)
Spark是MapReduce思想的一种更加精致和高效的实现。MapReduce有很多具体不同的实现,例如hadoop的marreduce基本的计算流程如下:首先是jvm为对象的并发执行的mapper,mapper中map的执行会产生输出数据,输出的数据会经过partitioner指定的规则放到Local FileSystem中,然后在经由shuffle,sort,aggregate编程Reducer中的reduce的输入,执行reduce产生最终执行结果;hadoop maprduce执行的流程虽然简单,但是过于死板,尤其是在构造复杂算法(迭代)时候非常不利于算法的实现,且执行效率极其低下。
Spark算法构造和物理执行时最最基本的核心:最大化pipeline!
基于pipeline的思想,数据被使用的时候才开始计算,从数据流动的视角来说,是数据流动到计算的位置!!!实质上从逻辑的角度来看,是算子在数据上流动!
从算法构建的角度而言:肯定是算子作用于数据,所以是算子在数据上流动;方便算法的构建!
从物理执行的角度而言:是数据流动到计算的位置!
对于pipeline而言,数据计算的位置就是每个stage中最后的rdd,一个震撼人心的内幕真相就是:每个stage中除了最后一个rdd算子是真实的以外,以前的算子都是假的!!!
由于计算的lazy特性,导致计算从后往前回溯,形成computing chain,导致的结果就是需要首先计算出具体一个stage内部左侧的rdd中本次计算依赖的partition。
三、窄依赖的物理执行内幕
一个stage内部的rdd都是窄依赖,窄依赖计算本身是逻辑上上看是从stage内部最左侧的rdd开始立即计算的,根据computing chain,数据(record)从一个计算步骤流动到下一个计算步骤,以此类推,直到计算到stage内部的最后一个rdd来产生计算结果。
Computingchain(根据依赖建立的)的构建是从后往前回溯,而实际的物理计算是让数据从前往后在算子上流动,直到流动到不能在流动位置才开始计算下一个record。这就导致一个美好的结果:后面的rdd对前面的rdd的依赖虽然是partition级别的数据集合的依赖,但是并不需要父rdd把partition中所有的records计算完毕才整体往后流动数据进行计算,这就极大的提高了计算速率!
四、宽依赖物理执行内幕
必须等到依赖的父stage中的最后一个rdd全部彻底计算完毕,才能够计算shuffle来计算当前的stage!
Rdd中的getDependencies负责确定rdd的之间的依赖关系。
作业:我理解中spark job的物理执行
Job由action触发,在diriver端中dagschedule把依赖划分成stage(taskset),然后再经由taskchedule根据scheduleBackend的掌握资源信息,提交task(partition)在executoe线程池执行。
本文深入探讨了Spark中Pipeline的工作原理,包括窄依赖和宽依赖的物理执行内幕,以及如何通过最大化Pipeline来提高计算效率。
13万+

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



