深度理解篇之Spark语义-个人拙见

Spark语义

Spark是一个分布式计算程序,他是大数据的计算引擎层面,在计算引擎层面,分为两大类,一类是属于流式计算,一类是数据批量计算,流计算里面是storm、flink,批计算里面是map reduce 和spark,想理清楚spark和MapReudce做对比,首先着两者的对比,就是mapreduce很慢,spark很快,那么为什么spark很快,首先不是基于内存的,由于每个stage计算完毕都是落地写磁盘,然后只要是shuffle都是这样的一个流程,虽然说spark官方的论文是computer on memory但是他的实现是内存模型,什么是基于内存计算的呢?基于内存计算的是由impala,只有流式是没有shuffle的读和写的过程,不需要将数据写到磁盘,再进行拉取数据,像storm和flink我们可以说是基于内存基于流式的,从一块网卡进来,基于内存,然后从另一块网卡出去.Spark和MapReduce一定是在一个节点当中拿着一批数据过滤完之后写到磁盘,所以说快慢并不是这个点。

为什么Spark比MapRedcue快?

首先第一点,只要是Spark,都有application分布式计算程序,SparkSubmit提交了一个spark application应用程序,MapReduce也会有application应用程序,都是一个Application 但是在MapReduce当中有1个job,MR是提交一次作业有一个作业,但是在Spark中提交一次作业他会有n个job,比如说提交了一个spark show的应用程序,底层也是提交了一次spark application,写一个application代码程序跑一个job,如果不停止,一直写application 应用程序,那么会有无限个job。但是MapReduce中只有一个job,而spark中有无限多个job,从这个语义上去理解,在Mapreduce当中如果想做一个复杂计算的话,一个application的一个job是不能完成的,它一定会有多个job,形成一个job链,但在Spark中一个application书写多个action算子,就可以完成这个复杂计算,两者的速度差就出现了,因为application都是从JVM启动的过程,如果MR任务是一个作业链,也就意味着启动一个进程跑一次job,跑完之后,进程关闭消失,然后又开始启动,跑下一个job,完成后再次关闭进程,这样直到整个task任务执行完毕,启动消亡,启动消亡,到Spark中是什么样的呢?所有的executor就像是进程,启动executor之后,意味着application启动完毕了,然后无非就是通过线程或者反序列化的方式发送任务,这时候都是再执行任务,执行很多的任务,两着的进程的损耗时间是不一样的。MapReduce和Spark的执行方式比如这一个例子:需要听歌、上网、打游戏,MapRecue的执行流程会是,开机-听歌-关机-开机-上网-关机-开启-打游戏-关机,每次做完一件事都会关机开机,而Spark就是开机-听歌-上网-打游戏-关机。这些描述就是第一方面。

在来说在两个计算框架当中可能有一个job或者若干着job,面对一个MR job会有几个阶段呢?要么是Map阶段和Reduce阶段,要么只有Map阶段,最多两个阶段,最少一个阶段,但是在Spark当中一个Job会有多少个阶段呢?N个阶段,阶段与阶段之间是什么衔接的呢?是靠的shuffle来衔接的,但是再去对比,如果在MapReduce当中,如果计算很复杂,会有很多个job,job之间的阶段衔接是shuffle,但是两个job之间的衔接是HDFS,因为前一个job的结果写到HDFS后一个job要基于它计算,那么在Spark当中,因为一个job,有n个阶段,那么中间就不需要像HDFS那样的存储过程了,它的所有阶段之间就是靠的shuffle来衔接的,这也是一个特征,他们阶段的数量有差异,阶段之间的衔接不同,job的数量不一样,当然每个阶段的任务是相似的两个在各自的框架当中,都会有各自的并行的任务,任务数都是n,都是取决于块的数量,这是没有太多争议的,无论是Spark还是MapReduce,像application job tage都是逻辑的,其中只有task是物理的,而且task尽量是向数据移动,虽然两者里面都有n个任务,但是两者的task任务的形式是不一样的,mapRedcue中的任务是进程级别的,Spark中的任务是线程的,因为Executor中会抛线程池,来一个任务,就会跑出一个线程来跑任务的,把这个思路率清楚之后

两者的编程模型,在MapReduce中的编程模型当中是,最核心的是map方法和reduce方法,mapReduce的输入路径叫做输入集,只不过没有api的表示而已,map是作用在输入集的身上,map输出落地的中间结果,就是中间集,中间集被Reduce拉走之后,计算的结果叫做结果集,MR中没有响应的api去表示这些,只是使用map和reduce,但是在spark中这一问题被修正了。

因为在spark编程模型是什么呢?

RDD

弹性分布式数据集,每一次变化都是由一个RDD来代表,通过调用一个方法后,经过方法逻辑的处理会编程另外一种RDD,这样又是新的一种RDD代表了,所以说数据集的概念就出现了。一谈到RDD就要说它的五大特性了,

  1. 一个RDD是由一系列的partition分区组成的,为什么说RDD是由一系列分区组成的呢?会到Spark定义,它叫分布式计算框架,如果你的数据集是单机的,那么就没有意义了,RDD的名词是什么意思呢?DataSet就是数据集的概念,比如Scala当中map ,list.set数据集的概念,Spark中数据集都可以使用foreach、flatMap,数据集都有这一类通用的算子,起始说RDD这三个单词不是白定义的,为什么后面定义的语义是通用的,分布式是什么?跟刚才的一个RDD是由一系列分区组成的挂上沟了,不同的分区会在不同的节点上的。
  2. 算子是作用的每一个分区上的,这句话也可以和分布式挂钩,因为在分布式计算当中,有这么一句话就是计算向数据移动,并行计算,所以这时候在所谓的dataset上调用了了所谓的map,map会变成很多个map,然后作用在每个分区上计算,也体现着计算向数据移动。
  3. RDD之间存在着依赖关系,这个依赖关系是什么呢?通俗的描述就是窄依赖和宽依赖,宽依赖可以说是shuffle依赖,因为源码中写的是shuffle dependence,没有宽这个单词,宽依赖就是shuffle依赖。什么是shuffle依赖呢?一对多,如果前面一个RDD的一个分区对应着下游的多个分区的话,就是一个shuffle。如果多个对应一个分区呢,当然是窄依赖了。比如说coalesce算子,减少分区,这个算子不是通过shuffle完成的而是通过IO来完成的,等于一个RDD中的分区,通过IO读取两个两个分区中的数据,读到本地,然后压缩成一个分区来,减少分区。为什么会有依赖关系这件事呢?依赖关系是建立stage用的,由于代码是线性的,那些代码应该放在一起,移动到一个数据位置,另外代码放在一起移动到另外的一块数据上,而代码的切割就是靠的就是RDD之间的依赖关系,如果都是窄依赖的话,他们都会划分到一个stage中,这个stage会翻译成很多个task,map阶段会有很多的并行的task,所以说只需要把一系列RDD之间的转化划分成一个stage,那么这个代码会根据可分区的数量划分成多份,然后进行计算,所以说shuffle依赖和窄依赖是确定stage划分的。问题:一个stage会被划分成多少个task,并行度是多少呢?会由最终的finalRDD决定的,因为shuffle是用来划分stage的,所以stage中的最后一个stage的最后一个RDD的分区数就是一个stage的并行度。
  4. 分区器是作用的K、V格式的RDD上的,由此可知RDD分为是K、V的和不是K、V的,数据集为什么要分成有KV和没有KV的呢?K、V的目的是什么呢?将数据的特征抽取成K,根据特征要去做汇聚,比如groupbykey,reduceByKey,SortByKey必须要知道key是什么,按照k去做分组或排序,所以只要是这种K、V的RDD都脱离不了汇聚。也就是说在上游的数据当中有一部分数据要跑到一个分区去,所以要给他们进行分区,利用到分区器,满足了相同的key为一组的思想。
  5. Partition向外提供最佳的计算位置,为了数据的本地化计算,比如说一个block块,有多个副本。最佳的位置就是有资源可移动的地方,移动过去之后,进行读取本地的这个数据块,这是移动和本地化读取。

这就是Spark的编程模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值